
<style>
  body{
    margin:0px;
    overflow:hidden;
    background:rgb(30,30,35);
    font-family:sans-serif;
    color:white;
  }
  select, button{
    background:none;
    -webkit-appearance:none;
    font-size:12px;
    color:silver;
    border: 1px solid gray;
    border-radius:2px;
    padding:1px 5px 1px 5px;
    margin:0px;
    outline: none;
    cursor:pointer;
  }
  select:hover, button:hover{
    outline: none;
    background:rgba(255,255,255,0.1);
  }
  option{
    background:rgb(30,30,35);
    color:silver;
  }
  div::-webkit-scrollbar {
    display: none;
  }
  div {
    -ms-overflow-style: none;
    scrollbar-width: none;
  }
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/codemirror.min.css">
<link rel="stylesheet" href="https://codemirror.net/5/theme/dracula.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/mode/simple.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/edit/matchbrackets.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/comment/comment.min.js"></script>
<script src="https://codemirror.net/mode/javascript/javascript.js"></script>
<script src="https://codemirror.net/mode/clike/clike.js"></script>
<script src="https://codemirror.net/mode/python/python.js"></script>
<script src="https://codemirror.net/mode/swift/swift.js"></script>
<script src="https://codemirror.net/mode/lua/lua.js"></script>
<script src="https://codemirror.net/mode/wast/wast.js"></script>

<script src="https://unpkg.com/typescript@4.0.3/lib/typescriptServices.js"></script>

<script src="waxc.js"></script>
<style>.CodeMirror { height: 100%; }</style>
<body>
  <div id="hd" style="position:absolute;left:0px;top:0px;width:100%;height:50px;overflow-x:scroll;overflow-y:hidden">
    <div id="hdin" style="width:2000px">
      <div style="position:absolute;left:9px;top:9px;">
        <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="32" height="32" viewBox="0, 0, 143.398, 155.887">
  <g id="Layer_1" transform="translate(-265.979, -593.56)">
    <path d="M265.979,626.943 L409.377,594.842 L409.377,749.033 L266.034,749.447 L265.979,626.943 z" fill="#000000"/>
    <path d="M275.586,705.402 L285.664,705.402 L289.297,724.598 L294.594,705.402 L304.648,705.402 L309.969,724.598 L313.602,705.402 L323.633,705.402 L316.063,739.762 L305.656,739.762 L299.633,718.129 L293.633,739.762 L283.227,739.762 z" fill="#FFFFFF"/>
    <path d="M348.266,734.09 L336.172,734.09 L334.508,739.762 L323.656,739.762 L336.57,705.402 L348.148,705.402 L361.063,739.762 L349.953,739.762 z M346.039,726.66 L342.242,714.309 L338.469,726.66 z" fill="#FFFFFF"/>
    <path d="M362.094,705.402 L373.789,705.402 L379.883,715.973 L385.789,705.402 L397.367,705.402 L386.68,722.043 L398.375,739.762 L386.445,739.762 L379.672,728.723 L372.875,739.762 L361.016,739.762 L372.875,721.856 z" fill="#FFFFFF"/>
    <g>
      <path d="M298.068,635.135 C286.588,635.135 277.281,625.828 277.281,614.348 C277.281,602.867 286.588,593.56 298.068,593.56 C309.549,593.56 318.856,602.867 318.856,614.348 C318.856,625.828 309.549,635.135 298.068,635.135 z" fill="#7A67FF"/>
      <path d="M324.927,632.51 C316.74,632.51 310.103,625.873 310.103,617.686 C310.103,609.499 316.74,602.862 324.927,602.862 C333.114,602.862 339.751,609.499 339.751,617.686 C339.751,625.873 333.114,632.51 324.927,632.51 z" fill="#7A67FF"/>
      <path d="M276.854,632.51 C272.014,632.51 268.09,628.586 268.09,623.746 C268.09,618.906 272.014,614.982 276.854,614.982 C281.694,614.982 285.618,618.906 285.618,623.746 C285.618,628.586 281.694,632.51 276.854,632.51 z" fill="#7A67FF"/>
      <path d="M277.281,622.882 L283.408,622.882 L283.408,671.897 L277.281,671.897 L277.281,622.882 z" fill="#7A67FF"/>
      <path d="M288.598,625.07 L299.777,625.07 L299.777,658.945 L288.598,658.945 L288.598,625.07 z" fill="#7A67FF"/>
      <path d="M307.089,625.07 L313.111,625.07 L313.111,686.762 L307.089,686.762 L307.089,625.07 z" fill="#7A67FF"/>
      <path d="M318.234,619.818 L323.854,619.818 L323.854,644.326 L318.234,644.326 L318.234,619.818 z" fill="#7A67FF"/>
      <path d="M280.344,678.899 C277.686,678.899 275.53,676.744 275.53,674.085 C275.53,671.426 277.686,669.271 280.344,669.271 C283.003,669.271 285.158,671.426 285.158,674.085 C285.158,676.744 283.003,678.899 280.344,678.899 z" fill="#7A67FF"/>
      <path d="M294.232,664.751 C291.169,664.751 288.686,662.268 288.686,659.205 C288.686,656.143 291.169,653.66 294.232,653.66 C297.294,653.66 299.777,656.143 299.777,659.205 C299.777,662.268 297.294,664.751 294.232,664.751 z" fill="#7A67FF"/>
      <path d="M310.261,694.654 C306.514,694.654 303.477,691.617 303.477,687.87 C303.477,684.124 306.514,681.087 310.261,681.087 C314.007,681.087 317.044,684.124 317.044,687.87 C317.044,691.617 314.007,694.654 310.261,694.654 z" fill="#7A67FF"/>
      <path d="M321.202,649.577 C318.906,649.577 317.044,647.716 317.044,645.42 C317.044,643.124 318.906,641.262 321.202,641.262 C323.498,641.262 325.359,643.124 325.359,645.42 C325.359,647.716 323.498,649.577 321.202,649.577 z" fill="#7A67FF"/>
      <path d="M344.61,619.818 C338.671,619.818 333.857,615.004 333.857,609.065 C333.857,603.126 338.671,598.312 344.61,598.312 C350.549,598.312 355.363,603.126 355.363,609.065 C355.363,615.004 350.549,619.818 344.61,619.818 z" fill="#7A67FF"/>
      <path d="M326.101,625.07 C318.712,625.07 312.722,619.08 312.722,611.691 C312.722,604.302 318.712,598.312 326.101,598.312 C333.49,598.312 339.48,604.302 339.48,611.691 C339.48,619.08 333.49,625.07 326.101,625.07 z" fill="#7A67FF"/>
    </g>
  </g>
</svg>

      </div>
      <div style="position:absolute;left:50px;top:8px;font-size:16px;font-weight:bold;">
        wax compiler
      </div>
      <div style="position:absolute;left:50px;top:27px;font-size:11px;color:gray">
        A tiny language designed to transpile to other languages.
      </div>

      <div style="position:absolute;left:365px;top:27px;position:absolute;font-size:11px;color:gray">
        Example:
      </div>
      <select id="selexam" style="position:absolute;left:420px;top:25px;">
        <option value="delaunay.wax">delaunay.wax</option><option value="fib.wax">fib.wax</option><option value="flocking.wax">flocking.wax</option><option value="helloworld.wax">helloworld.wax</option><option value="hilbert.wax">hilbert.wax</option><option value="kmeans.wax">kmeans.wax</option><option value="line.wax">line.wax</option><option value="nqueens.wax">nqueens.wax</option><option value="poissondisk.wax">poissondisk.wax</option><option value="quicksort.wax">quicksort.wax</option><option value="quine.wax">quine.wax</option><option value="raycast.wax">raycast.wax</option><option value="traceskeleton.wax">traceskeleton.wax</option><option value="turing.wax">turing.wax</option><option value="vororelax.wax">vororelax.wax</option>
      </select>

      <div style="position:absolute;left:550px;top:27px;position:absolute;font-size:11px;color:gray">
        Transpile&nbsp;to:
      </div>
      <select id="seltarg" style="position:absolute;left:620px;top:25px;" value="ts">
        <option value="c">C</option>
        <option value="cpp">C++</option>
        <option value="java">Java</option>
        <option selected="selected" value="ts">TypeScript</option>
        <option value="py">Python</option>
        <option value="cs">C#</option>
        <option value="swift">Swift</option>
        <option value="lua">Lua</option>
        <option value="wat">WebAssembly</option>
        <option value="json">JSON</option>
        <!--<option value="ast">Syntax Tree</option>-->
      </select>


      <div style="position:absolute;left:730px;top:27px;position:absolute;font-size:11px;color:gray">
        Realtime:
      </div>
      <select id="selreal" style="position:absolute;left:785px;top:25px;">
        <option>yes</option>
        <option>no</option>
      </select>

      <button id="butcomp" style="position:absolute;left:865px;top:25px;">
        Compile
      </button>

      <button id="butrunc" style="position:absolute;left:925px;top:25px;">
        Run
      </button>

    </div>
  </div>
  <div id="cl" style="position:absolute;left:0px;top:50px;width:50%;height:calc(100% - 50px)">
    
  </div>
  <div id="cr" style="position:absolute;left:50%;top:50px;width:50%;height:calc(100% - 50px)">
  </div>
  <div id="crimg" style="position:absolute;left:calc(50% + 30px);top:80px;z-index:1000;filter:invert(100%);"></div>
  <div id="ghub" style="opacity:50%;position:absolute;right:9px;top:8px;cursor:pointer;z-index:1000">
<svg fill="white" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="32" height="32" viewBox="0, 0, 32, 32">
    <path d="M15.999,-0 C7.163,-0 0,7.345 0,16.405 C0,23.653 4.584,29.802 10.942,31.972 C11.743,32.122 12.034,31.615 12.034,31.18 C12.034,30.792 12.021,29.759 12.013,28.391 C7.562,29.382 6.623,26.191 6.623,26.191 C5.895,24.296 4.846,23.791 4.846,23.791 C3.394,22.774 4.956,22.794 4.956,22.794 C6.562,22.91 7.407,24.485 7.407,24.485 C8.834,26.992 11.152,26.268 12.064,25.848 C12.209,24.788 12.622,24.065 13.079,23.655 C9.527,23.242 5.791,21.834 5.791,15.547 C5.791,13.757 6.415,12.292 7.438,11.145 C7.273,10.73 6.724,9.063 7.595,6.804 C7.595,6.804 8.938,6.363 11.995,8.486 C13.271,8.121 14.64,7.94 16,7.934 C17.359,7.94 18.728,8.121 20.006,8.486 C23.061,6.363 24.401,6.804 24.401,6.804 C25.275,9.063 24.726,10.73 24.561,11.145 C25.586,12.292 26.206,13.757 26.206,15.547 C26.206,21.85 22.465,23.236 18.9,23.642 C19.475,24.149 19.986,25.15 19.986,26.681 C19.986,28.873 19.967,30.643 19.967,31.18 C19.967,31.619 20.255,32.13 21.067,31.97 C27.42,29.796 32,23.651 32,16.405 C32,7.345 24.836,-0 15.999,-0"/>
</svg>
  </div>
</body>
<script>
var ghub = document.getElementById("ghub");
ghub.onmouseenter=function(){ghub.style.opacity=0.8}
ghub.onmouseleave=function(){ghub.style.opacity=0.5}
ghub.onclick=function(){document.location.href="https://github.com/LingDong-/wax"}
function ghubresize(){
  if (window.innerWidth<1024){
    ghub.style.top="58px";
  }else{
    ghub.style.top="8px";
  }
}
ghubresize();
window.addEventListener('resize', ghubresize);
</script>
<script>
  var examples = {"delaunay.wax":";; Delaunay Triangulation\n;; ported from Paul Bourke original C version:\n;; http://paulbourke.net/papers/triangulate/triangulate.c\n;; with original comments\n\n(@include math)\n\n(@define X 0)\n(@define Y 1)\n(@define FALSE 0)\n(@define TRUE 1)\n(@define P1 0)\n(@define P2 1)\n(@define P3 2)\n(@define EPSILON 0.0000001)\n\n;; Return TRUE if a point (xp,yp) is inside the circumcircle made up\n;; of the points (x1,y1), (x2,y2), (x3,y3)\n;; The circumcircle centre is returned in (xc,yc) and the radius r\n;; NOTE: A point on the edge is inside the circumcircle\n(func circumcircle (param xp float) (param yp float)\n\t(param x1 float) (param y1 float) (param x2 float) (param y2 float) (param x3 float) (param y3 float)\n\t(param xcycr (vec 3 float)) (result int)\n\n\t(let m1 float) (let m2 float)\n\t(let mx1 float) (let mx2 float)\n\t(let my1 float) (let my2 float)\n\t(let dx float) (let dy float) (let drsqr float)\n\t(let fabsy1y2 float (call fabs (- y1 y2)))\n\t(let fabsy2y3 float (call fabs (- y2 y3)))\n\t(let xc float)\n\t(let yc float)\n\t(let rsqr float)\n\n\t(if (&& (< fabsy1y2 @EPSILON) (< fabsy2y3 @EPSILON)) (then\n\t\t(return 0)\n\t))\n\t(if (< fabsy1y2 @EPSILON) (then\n\t\t(set m2 (- (/ (- x3 x2) (- y3 y2))))\n\t\t(set mx2 (/ (+ x2 x3) 2.0))\n\t\t(set my2 (/ (+ y2 y3) 2.0))\n\t\t(set xc (/ (+ x2 x1) 2.0))\n\t\t(set yc (+ (* m2 (- xc mx2)) my2))\n\t)(else (if (< fabsy2y3 @EPSILON) (then\n\t\t(set m1 (- (/ (- x2 x1) (- y2 y1))))\n\t\t(set mx1 (/ (+ x1 x2) 2.0))\n\t\t(set my1 (/ (+ y1 y2) 2.0))\n\t\t(set xc (/ (+ x3 x2) 2.0))\n\t\t(set yc (+ (* m1 (- xc mx1)) my1))\n\t)(else\n\t\t(set m1 (- (/ (- x2 x1) (- y2 y1))))\n\t\t(set m2 (- (/ (- x3 x2) (- y3 y2))))\n\t\t(set mx1 (/ (+ x1 x2) 2.0))\n\t\t(set mx2 (/ (+ x2 x3) 2.0))\n\t\t(set my1 (/ (+ y1 y2) 2.0))\n\t\t(set my2 (/ (+ y2 y3) 2.0))\n\t\t(set xc (/ (+ (* m1 mx1) (- (* m2 mx2)) my2 (- my1) ) (- m1 m2) ))\n\t\t(if (> fabsy1y2 fabsy2y3) (then\n\t\t\t(set yc (+ (* m1 (- xc mx1)) my1))\n\t\t)(else\n\t\t\t(set yc (+ (* m2 (- xc mx2)) my2))\n\t\t))\n\t))))\n\t(set dx (- x2 xc))\n\t(set dy (- y2 yc))\n\t(set rsqr (+ (* dx dx) (* dy dy)))\n\t(set dx (- xp xc))\n\t(set dy (- yp yc))\n\t(set drsqr (+ (* dx dx) (* dy dy)))\n\n\t(set xcycr @X xc)\n\t(set xcycr @Y yc)\n\t(set xcycr 2 rsqr)\n\n\t(return (<= (- drsqr rsqr) @EPSILON))\n)\n\n;; Triangulation subroutine\n;; Takes as input vertices in array pxyz\n;; Returned is a list of triangular faces\n;; These triangles are arranged in a consistent clockwise order.\n;; The vertex array must be sorted in increasing x values\n(func delaunaytriangulate (param pxyz (arr (vec 2 float))) (result (arr (vec 3 int)))\n\t(let nv int (# pxyz))\n\t(let inside int)\n\t(let xp float) (let yp float)\n\t(let x1 float) (let y1 float)\n\t(let x2 float) (let y2 float)\n\t(let x3 float) (let y3 float)\n\t(let xmin float) (let xmax float)\n\t(let ymin float) (let ymax float)\n\t(let xmid float) (let ymid float)\n\t(let dx float) (let dy float) (let dmax float)\n\n\t(local xcycr (vec 3 float) (alloc (vec 3 float)))\n\t(local complete (arr int) (alloc (arr int)))\n\n\t(let v (arr (vec 3 int)) (alloc (arr (vec 3 int))))\n\n\t(if (< (# pxyz) 3) (then\n\t\t(return v)\n\t))\n\n\t;; Find the maximum and minimum vertex bounds.\n\t;; This is to allow calculation of the bounding triangle\n\t(set xmin (get pxyz 0 @X))\n\t(set ymin (get pxyz 0 @Y))\n\t(set xmax xmin)\n\t(set ymax ymin)\n\t(for i 1 (< i nv) 1 (do\n\t\t(if (< (get pxyz i @X) xmin) (then (set xmin (get pxyz i @X)) ))\n\t\t(if (> (get pxyz i @X) xmax) (then (set xmax (get pxyz i @X)) ))\n\t\t(if (< (get pxyz i @Y) ymin) (then (set ymin (get pxyz i @Y)) ))\n\t\t(if (> (get pxyz i @Y) ymax) (then (set ymax (get pxyz i @Y)) ))\n\t))\n\n\t(set dx (- xmax xmin))\n\t(set dy (- ymax ymin))\n\t(set dmax (? (> dx dy) dx dy))\n\t(set xmid (/ (+ xmax xmin) 2))\n\t(set ymid (/ (+ ymax ymin) 2))\n\t\n\t;; Set up the supertriangle\n\t;; This is a triangle which encompasses all the sample points.\n\t;; The supertriangle coordinates are added to the end of the\n\t;; vertex list. The supertriangle is the first triangle in\n\t;; the triangle list.\n\n\t(insert pxyz (# pxyz) (alloc (vec 2 float) \n\t\t(- xmid (* 2.0 dmax))\n\t\t(- ymid dmax)\n\t))\n\t(insert pxyz (# pxyz) (alloc (vec 2 float)\n\t\txmid\n\t\t(+ ymid (* 2.0 dmax))\n\t))\n\t(insert pxyz (# pxyz) (alloc (vec 2 float)\n\t\t(+ xmid (* 2.0 dmax))\n\t\t(- ymid dmax)\n\t))\n\t(insert v 0 (alloc (vec 3 int)\n\t\tnv\n\t\t(+ nv 1)\n\t\t(+ nv 2)\n\t))\n\n\t(insert complete 0 @FALSE)\n\t\n\t;; Include each point one at a time into the existing mesh\n\t(for i 0 (< i nv) 1 (do\n\t\t(set xp (get pxyz i @X))\n\t\t(set yp (get pxyz i @Y))\n\t\t\n\t\t(local edges (arr (vec 2 int)) (alloc (arr (vec 2 int))))\n\n\t\t;; Set up the edge buffer.\n\t\t;; If the point (xp,yp) lies inside the circumcircle then the\n\t\t;; three edges of that triangle are added to the edge buffer\n\t\t;; and that triangle is removed.\n\n\t\t(for j (- (# v) 1) (>= j 0) -1 (do\n\t\t\t(if (! (get complete j)) (then\n\t\t\t\t(set x1 (get pxyz (get v j @P1) @X))\n\t\t\t\t(set y1 (get pxyz (get v j @P1) @Y))\n\t\t\t\t(set x2 (get pxyz (get v j @P2) @X))\n\t\t\t\t(set y2 (get pxyz (get v j @P2) @Y))\n\t\t\t\t(set x3 (get pxyz (get v j @P3) @X))\n\t\t\t\t(set y3 (get pxyz (get v j @P3) @Y))\n\t\t\t\t(set inside (call circumcircle xp yp x1 y1 x2 y2 x3 y3 xcycr))\n\n\t\t\t\t(let xc float (get xcycr @X))\n\t\t\t\t(let r float (get xcycr 2))\n\t\t\t\t(if (&& (< xc xp) (> (* (- xp xc) (- xp xc)) r) ) (then\n\t\t\t\t\t(set complete j @TRUE)\n\t\t\t\t))\n\t\t\t\t(if inside (then\n\t\t\t\t\t(insert edges (# edges) (alloc (vec 2 int) (get v j @P1) (get v j @P2)))\n\t\t\t\t\t(insert edges (# edges) (alloc (vec 2 int) (get v j @P2) (get v j @P3)))\n\t\t\t\t\t(insert edges (# edges) (alloc (vec 2 int) (get v j @P3) (get v j @P1))) \n\t\t\t\t\t(free (get v j))\n\t\t\t\t\t(remove v j 1)\n\t\t\t\t\t(remove complete j 1)\n\t\t\t\t))\n\t\t\t))\n\t\t))\n\t\t;; Tag multiple edges\n\t\t;; Note: if all triangles are specified anticlockwise then all\n\t\t;;       interior edges are opposite pointing in direction.\n\t\t(for j 0 (< j (- (# edges) 1)) 1 (do\n\t\t\t(for k (+ j 1) (< k (# edges)) 1 (do\n\t\t\t\t(if (&&\n\t\t\t\t\t(= (get edges j @P1) (get edges k @P2))\n\t\t\t\t\t(= (get edges j @P2) (get edges k @P1))\n\t\t\t\t) (then\n\t\t\t\t\t(set (get edges j) @P1 -1)\n\t\t\t\t\t(set (get edges j) @P2 -1)\n\t\t\t\t\t(set (get edges k) @P1 -1)\n\t\t\t\t\t(set (get edges k) @P2 -1)\n\t\t\t\t))\n\t\t\t\t;; Shouldn't need the following, see note above\n\t\t\t\t(if (&&\n\t\t\t\t\t(= (get edges j @P1) (get edges k @P1))\n\t\t\t\t\t(= (get edges j @P2) (get edges k @P2))\n\t\t\t\t) (then\n\t\t\t\t\t(set (get edges j) @P1 -1)\n\t\t\t\t\t(set (get edges j) @P2 -1)\n\t\t\t\t\t(set (get edges k) @P1 -1)\n\t\t\t\t\t(set (get edges k) @P2 -1)\n\t\t\t\t))\n\t\t\t))\n\t\t))\n\t\t\n\t\t;; Form new triangles for the current point\n\t\t;; Skipping over any tagged edges.\n\t\t;; All edges are arranged in clockwise order.\n\t\t(for j 0 (< j (# edges)) 1 (do\n\t\t\t(if (||\n\t\t\t\t(< (get edges j @P1) 0)\n\t\t\t\t(< (get edges j @P2) 0)\n\t\t\t) (then) (else\n\t\t\t\t(insert v (# v) (alloc (vec 3 int)\n\t\t\t\t\t(get edges j @P1)\n\t\t\t\t\t(get edges j @P2)\n\t\t\t\t\ti\n\t\t\t\t))\n\t\t\t\t(insert complete (# complete) @FALSE)\n\t\t\t))\n\t\t\t(free (get edges j))\n\t\t))\n\t))\n\t;; Remove triangles with supertriangle vertices\n\t;; These are triangles which have a vertex number greater than nv\n\t(for i (- (# v) 1) (>= i 0) -1 (do\n\t\t(if (||\n\t\t\t(>= (get v i @P1) nv)\n\t\t\t(>= (get v i @P2) nv)\n\t\t\t(>= (get v i @p3) nv)\n\t\t)(then\n\t\t\t(free (get v i))\n\t\t\t(remove v i 1)\n\t\t))\n\t))\n\n\t(return v)\n)\n\n(func comparex (param v1 (vec 2 float)) (param v2 (vec 2 float)) (result int)\n\t(if (< (get v1 @X) (get v2 @X)) (then\n\t\t(return -1)\n\t)(else (if (> (get v1 @X) (get v2 @X)) (then\n\t\t(return 1)\n\t))))\n\t(return 0)\n)\n\n; qucksort by ascending x coordinate\n(func sortbyx (param A (arr (vec 2 float))) (param lo int) (param hi int)\n\t(if (>= lo hi) (then\n\t\t(return)\n\t))\n\t(let pivot (vec 2 float) (get A lo))\n\t(let left  int lo)\n\t(let right int hi)\n\t(while (<= left right) (do\n\t\t(while (< (call comparex (get A left) pivot) 0) (do\n\t\t\t(set left (+ left 1))\n\t\t))\n\t\t(while (> (call comparex (get A right) pivot) 0) (do\n\t\t\t(set right (- right 1))\n\t\t))\n\t\t(if (<= left right) (then\n\t\t\t(let tmp (vec 2 float) (get A left))\n\t\t\t(set A left (get A right))\n\t\t\t(set A right tmp)\n\t\t\t(set left  (+ left 1))\n\t\t\t(set right (- right 1))\n\t\t))\n\t))\n\t(call sortbyx A lo right)\n\t(call sortbyx A left hi)\n)\n\n; render triangulation result to SVG string\n(func render_svg (param w int) (param h int) \n\t(param pxyz (arr (vec 2 float))) \n\t(param triangles (arr (vec 3 int))) \n\t(result str)\n\n\t(let s str (alloc str \"<svg version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" width=\\\"\"))\n\t(<< s (cast w str))\n\t(<< s \"\\\" height=\\\"\")\n\t(<< s (cast h str))\n\t(<< s \"\\\">\")\n\n\t(for i 0 (< i (# pxyz)) 1 (do\n\t\t(<< s \"<circle cx=\\\"\")\n\t\t(<< s (cast (get pxyz i @X) str))\n\t\t(<< s \"\\\" cy=\\\"\")\n\t\t(<< s (cast (get pxyz i @Y) str))\n\t\t(<< s \"\\\" r=\\\"2\\\" />\")\n\t))\n\n\t(for i 0 (< i (# triangles)) 1 (do\n\t\t(<< s \"<path d=\\\"M\")\n\t\t(<< s (cast (get pxyz (get triangles i @P1) @X) str))\n\t\t(<< s \",\")\n\t\t(<< s (cast (get pxyz (get triangles i @P1) @Y) str))\n\t\t(<< s \" L\")\n\t\t(<< s (cast (get pxyz (get triangles i @P2) @X) str))\n\t\t(<< s \",\")\n\t\t(<< s (cast (get pxyz (get triangles i @P2) @Y) str))\n\t\t(<< s \" L\")\n\t\t(<< s (cast (get pxyz (get triangles i @P3) @X) str))\n\t\t(<< s \",\")\n\t\t(<< s (cast (get pxyz (get triangles i @P3) @Y) str))\n\t\t(<< s \" z\\\" fill=\\\"rgba(0,0,0,0.1)\\\" stroke-width=\\\"1\\\" stroke=\\\"black\\\"/>\")\n\t))\n\n\t(<< s \"</svg>\")\n\t(return s)\n)\n\n;; test triangulation\n(func main (result int)\n\t(local pxyz (arr (vec 2 float)) (alloc (arr (vec 2 float))))\n\t(let w int 400)\n\t(let h int 400)\n\t(for i 0 (< i 200) 1 (do\n\t\t(insert pxyz (# pxyz) (alloc (vec 2 float)\n\t\t\t(* (call random) w)\n\t\t\t(* (call random) h)\n\t\t))\n\t))\n\t(call sortbyx pxyz 0 (- (# pxyz) 1))\n\t(local triangles (arr (vec 3 int)) (call delaunaytriangulate pxyz))\n\t(local s str (call render_svg w h pxyz triangles))\n\t(print s)\n\t(for i 0 (< i (# triangles)) 1 (do\n\t\t(free (get triangles i))\n\t))\n\t(for i 0 (< i (# pxyz)) 1 (do\n\t\t(free (get pxyz i))\n\t))\n\t(return 0)\n)\n\n","fib.wax":";; Simple recursive function to compute\n;; Fibonacci numbers\n\n(func fib (param i int) (result int)\n\t(if (<= i 1) (then\n\t\t(return i)\n\t))\n\t(return (+\n\t\t(call fib (- i 1))\n\t\t(call fib (- i 2))\n\t))\n)\n\n(func main (result int)\n\t(let x int (call fib 9))\n\t(print x)\n\t(return 0)\n)\n\n","flocking.wax":";; flocking.wax\n;; flocking \"boid\" simulation\n;; ported from Processing example:\n;; https://processing.org/examples/flocking.html\n;; including original comments\n\n(@include math)\n\n;; math constants\n(@define PI         3.1415926536)\n(@define TWO_PI     6.2831853072)\n(@define HALF_PI    1.5707963268)\n(@define QUARTER_PI 0.7853981634)\n\n;; simulation constants\n(@define WIDTH    640) ; dimension of the world (for wraparound)\n(@define HEIGHT   360)\n(@define S        0.1) ; scaling to display with ASCII art\n(@define W         64) ; columns of ASCII art\n(@define H         36) ; rows ..\n(@define WxH     2304) ; rows x columns\n\n(@define FRAMES    5000) ; number of frames to simulate\n(@if TARGET_TS 1         ; do less frames in browsers\n\t(@define FRAMES 200) ; so it doesn't look like hanging :)\n)\n\n;; The Boid class\n(struct boid\n\t(let position (vec 2 float))\n\t(let velocity (vec 2 float))\n\t(let acceleration (vec 2 float))\n\t(let r float)\n\t(let maxforce float) ; Maximum steering force\n\t(let maxspeed float) ; Maximum speed\n)\n\n\n;; ===== \"polyfill\" Processing vector utils =====\n(func v_mult (param v (vec 2 float)) (param x float)\n\t(set v 0 (* (get v 0) x))\n\t(set v 1 (* (get v 1) x))\n)\n\n(func v_add (param v (vec 2 float)) (param u (vec 2 float))\n\t(set v 0 (+ (get v 0) (get u 0)))\n\t(set v 1 (+ (get v 1) (get u 1)))\n)\n(func v_sub (param v (vec 2 float)) (param u (vec 2 float))\n\t(set v 0 (- (get v 0) (get u 0)))\n\t(set v 1 (- (get v 1) (get u 1)))\n)\n(func v_copy (param v (vec 2 float))\n\t(result (vec 2 float))\n\t(return (alloc (vec 2 float)\n\t\t(get v 0)\n\t\t(get v 1)\n\t))\n)\n(func v_dist (param v (vec 2 float)) (param u (vec 2 float))\n\t(result float)\n\n\t(return (call sqrt (+\n\t\t(call pow (- (get v 0) (get u 0)) 2)\n\t\t(call pow (- (get v 1) (get u 1)) 2)\n\t)))\n)\n(func v_mag\n\t(param v (vec 2 float))\n\t(result float)\t\n\t(return (call sqrt\n\t\t(+\n\t\t\t(* (get v 0) (get v 0))\n\t\t\t(* (get v 1) (get v 1))\n\t\t)\n\t))\n)\n(func v_normalize\n\t(param v (vec 2 float))\n\t(let l float (call v_mag v))\n\t(set v 0 (/ (get v 0) l))\n\t(set v 1 (/ (get v 1) l))\n)\n(func v_limit (param v (vec 2 float)) (param m float)\n\t(let l float (call v_mag v))\n\t(if (< l m) (then\n\t\t(return)\n\t))\n\t(call v_normalize v)\n\t(call v_mult v m)\n)\n\n(func boid_new (param x float) (param y float)\n\t(result (struct boid))\n\n\t(let b (struct boid) (alloc (struct boid)))\n\t(set b acceleration (alloc (vec 2 float)))\n\n\t(let angle float (* (call random) @TWO_PI))\n\t(set b velocity (alloc (vec 2 float)\n\t\t(call cos angle)\n\t\t(call sin angle)\n\t))\n\t(set b position (alloc (vec 2 float) x y ))\n\n\t(set b r 2.0)\n\t(set b maxspeed 2.0)\n\t(set b maxforce 0.03)\n\n\t(return b)\n)\n\n(func boid_app_force \n\t(param B (struct boid)) \n\t(param force (vec 2 float)) \n\t; We could add mass here if we want A = F / M\n\t(call v_add (get B acceleration) force)\n)\n\n;; Separation\n;; Method checks for nearby boids and steers away\n(func boid_separate\n\t(param B (struct boid)) \n\t(param boids (arr (struct boid)))\n\t(result (vec 2 float))\n\n\t(let desiredseparation float 25.0)\n\t(let steer (vec 2 float) (alloc (vec 2 float)))\n\t(let count int 0)\n\n\t; For every boid in the system, check if it's too close\n\t(for i 0 (< i (# boids)) 1 (do\n\t\t(let other (struct boid) (get boids i))\n\t\t(let d float (call v_dist (get B position) (get other position)))\n\t\t; If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself)\n\t\t(if (&& (> d 0) (< d desiredseparation)) (then\n\t\t\t; Calculate vector pointing away from neighbor\n\t\t\t(local diff (vec 2 float) (call v_copy (get B position)))\n\t\t\t(call v_sub diff (get other position))\n\t\t\t(call v_normalize diff)\n\t\t\t(call v_mult diff (/ 1.0 d)) ; Weight by distance\n\t\t\t(call v_add steer diff)\n\t\t\t(set count (+ 1 count))      ; Keep track of how many\n\t\t))\n\t))\n\t; Average -- divide by how many\n\t(if (> count 0) (then\n\t\t(call v_mult steer (/ 1.0 count))\n\t))\n\t; As long as the vector is greater than 0\n\t(if (> (call v_mag steer) 0) (then\n\t\t; Implement Reynolds: Steering = Desired - Velocity\n\t\t(call v_normalize steer)\n\t\t(call v_mult steer (get B maxspeed))\n\t\t(call v_sub steer (get B velocity))\n\t\t(call v_limit steer (get B maxforce))\n\t))\n\t(return steer)\n)\n\n;; Alignment\n;; For every nearby boid in the system, calculate the average velocity\n(func boid_align \n\t(param B (struct boid)) \n\t(param boids (arr (struct boid)))\n\t(result (vec 2 float))\n\n\t(let neighborv_dist float 50)\n\t(let sum (vec 2 float) (alloc (vec 2 float)))\n\t(let count int 0)\n\t(for i 0 (< i (# boids)) 1 (do\n\t\t(let other (struct boid) (get boids i))\n\t\t(let d float (call v_dist (get B position) (get other position)))\n\t\t(if (&&\n\t\t\t(> d 0)\n\t\t\t(< d neighborv_dist)\n\t\t)(then\n\t\t\t(call v_add sum (get other velocity))\n\t\t\t(set count (+ 1 count))\n\t\t))\n\t))\n\t(if (> count 0) (then\n\t\t(call v_mult sum (/ 1.0 count))\n\t\t; Implement Reynolds: Steering = Desired - Velocity\n\t\t(call v_normalize sum)\n\t\t(call v_mult sum (get B maxspeed))\n\t\t(call v_sub sum (get B velocity))\n\t\t(call v_limit sum (get B maxforce))\n\t\t(return sum)\n\t))\n\t(call v_mult sum 0)\n\t(return sum)\n\t\n)\n\n;; A method that calculates and applies a steering force towards a target\n;; STEER = DESIRED MINUS VELOCITY\n(func boid_seek \n\t(param B (struct boid))\n\t(param target (vec 2 float))\n\n\t(call v_sub target (get B position))\n\t(call v_normalize target)\n\t(call v_mult target (get B maxspeed))\n\n\t; Steering = Desired minus Velocity\n\t(call v_sub target (get B velocity))\n\t(call v_limit target (get B maxforce)) ; Limit to maximum steering force\n)\n\n\n;; Cohesion\n;; For the average position (i.e. center) of all nearby boids, calculate steering vector towards that position\n(func boid_cohesion\n\t(param B (struct boid)) \n\t(param boids (arr (struct boid)))\n\t(result (vec 2 float))\n\n\t(let neighbordist float 50)\n\t(let sum (vec 2 float) (alloc (vec 2 float))) ; Start with empty vector to accumulate all positions\n\t(let count int 0)\n\t(for i 0 (< i (# boids)) 1 (do\n\t\t(let other (struct boid) (get boids i))\n\t\t(let d float (call v_dist (get B position) (get other position)))\n\t\t(if (&&\n\t\t\t(> d 0)\n\t\t\t(< d neighbordist)\n\t\t)(then\n\t\t\t(call v_add sum (get other position)) ; Add position\n\t\t\t(set count (+ 1 count))\n\t\t))\n\t))\n\t(if (> count 0) (then\n\t\t(call v_mult sum (/ 1.0 count))\n\t\t(call boid_seek B sum) ; Steer towards the position\n\t\t(return sum)\n\t))\n\t(call v_mult sum 0)\n\t(return sum)\n\t\n)\n\n\n;;  We accumulate a new acceleration each time based on three rules\n(func boid_flock \n\t(param B (struct boid)) \n\t(param boids (arr (struct boid)))\n\n\t(local sep (vec 2 float) (call boid_separate B boids)) ; Separation\n\t(local ali (vec 2 float) (call boid_align    B boids)) ; Alignment\n\t(local coh (vec 2 float) (call boid_cohesion B boids)) ; Cohesion\n\n\t; Arbitrarily weight these forces\n\t(call v_mult sep 1.5)\n\t(call v_mult ali 1.0)\n\t(call v_mult coh 1.0)\n\n\t; Add the force vectors to acceleration\n\t(call boid_app_force B sep)\n\t(call boid_app_force B ali)\n\t(call boid_app_force B coh)\n)\n\n;; Wraparound\n(func boid_borders (param B (struct boid))\n\t(let r float (get B r))\n\t(if (< (get B position 0) (- r)) (then\n\t\t(set (get B position) 0 (+ @WIDTH r))\n\t))\n\t(if (< (get B position 1) (- r)) (then\n\t\t(set (get B position) 1 (+ @HEIGHT r))\n\t))\n\t(if (> (get B position 0) (+ @WIDTH r)) (then\n\t\t(set (get B position) 0 (- r))\n\t))\n\t(if (> (get B position 1) (+ @HEIGHT r)) (then\n\t\t(set (get B position) 1 (- r))\n\t))\n\n)\n\n;; Method to update position\n(func boid_update (param B (struct boid))\n\t; Update velocity\n\t(call v_add (get B velocity) (get B acceleration))\n\t; Limit speed\n\t(call v_limit (get B velocity) (get B maxspeed))\n\t(call v_add (get B position) (get B velocity))\n\t; Reset accelertion to 0 each cycle\n\t(call v_mult (get B acceleration) 0)\n)\n\n\n(func boid_run (param B (struct boid)) (param boids (arr (struct boid)))\n\t(call boid_flock B boids)\n\t(call boid_update B)\n\t(call boid_borders B)\n)\n\n(func boid_free (param B (struct boid))\n\t(free (get B position))\n\t(free (get B acceleration))\n\t(free (get B velocity))\n\t(free B)\n)\n\n;; plot the flock with 2d ascii art\n(func flock_plot (param boids (arr (struct boid))) (param num int)\n\t(local pix \n\t\t(vec @WxH int) \n\t\t(alloc (vec @WxH int))\n\t)\n\t(for i 0 (< i (# boids)) 1 (do\n\t\t(let x int (* (get boids i position 0) @S))\n\t\t(let y int (* (get boids i position 1) @S))\n\t\t(if (&&\n\t\t\t(>= y 0) (>= x 0)\n\t\t\t(< y @H) (< x @W)\n\t\t)(then\n\n\t\t\t(let ang float (call atan2 \n\t\t\t\t(get boids i velocity 1)\n\t\t\t\t(get boids i velocity 0)\n\t\t\t))\n\t\t\t(let c int)\n\t\t\t(if (&& (>= ang (- @QUARTER_PI))              (< ang @QUARTER_PI))             (then (set c '>')))\n\t\t\t(if (&& (>= ang @QUARTER_PI)                  (< ang (+ @HALF_PI @QUARTER_PI)))(then (set c 'v')))\n\t\t\t(if (&& (>= ang (- (+ @HALF_PI @QUARTER_PI))) (< ang (- @QUARTER_PI)))         (then (set c '^')))\n\t\t\t(if (! c) (then (set c '<')))\n\t\t\t\n\t\t\t(set pix (+ (* y @W) x) c)\n\t\t))\n\t))\n\t(local s str (alloc str \"FRAME: \"))\n\t(<< s (cast num str))\n\t(for i 0 (< i @WxH) 1 (do\n\t\t(if (! (% i @W)) (then\n\t\t\t(<< s \"\\n\")\n\t\t))\n\t\t(<< s (? (get pix i) (get pix i) ' '))\n\t))\n\t(print s)\n)\n\n;; run the simulation\n(func main (result int)\n\t(let flock (arr (struct boid)) (alloc (arr (struct boid))))\n\t(for i 0 (< i 100) 1 (do\n\t\t(insert flock (# flock)\n\t\t\t(call boid_new (/ @WIDTH 2.0) (/ @HEIGHT 2.0))\n\t\t)\n\t))\n\t(for k 0 (< k @FRAMES) 1 (do\n\t\t(for i 0 (< i (# flock)) 1 (do\n\t\t\t(call boid_run (get flock i) flock)\n\t\t))\n\t\t(if (! (% k 20)) (then\n\t\t\t(call flock_plot flock k)\n\t\t))\n\t))\n\t(for i 0 (< i (# flock)) 1 (do\n\t\t(call boid_free (get flock i))\n\t))\n\t(free flock)\n\t(return 0)\n)\n\n\n\n","helloworld.wax":"(func main (result int)\n  (print \"hello world!\")\n  (return 0)\n)","hilbert.wax":";; Hilbert Curve\n;; The space-filling curve desribed by David Hilbert in 1891\n;; ported from:\n;; https://en.wikipedia.org/wiki/Hilbert_curve\n;; http://www.rosettacode.org/wiki/Hilbert_curve#Java\n\n;; rotate/flip a quadrant appropriately\n(func rot (param n int) (param xy (vec 2 int)) (param rx int) (param ry int)\n  (if (= ry 0) (then\n    (if (= rx 1) (then\n      (set xy 0 (- (- n 1) (get xy 0)))\n      (set xy 1 (- (- n 1) (get xy 1)))\n    ))\n    ; swap x and y\n    (let t int (get xy 0))\n    (set xy 0 (get xy 1))\n    (set xy 1 t)\n  ))\n)\n\n;; convert d to (x,y)\n(func d2xy (param n int) (param d int) (param xy (vec 2 int))\n  (let rx int)\n  (let ry int)\n  (let t int d)\n  (set xy 0 0)\n  (set xy 1 0)\n  (for s 1 (< s n) s (do\n    (set rx (& 1 (/ t 2)))\n    (set ry (& 1 (^ t rx)))\n    (call rot s xy rx ry)\n    (set xy 0 (+ (get xy 0) (* s rx)))\n    (set xy 1 (+ (get xy 1) (* s ry)))\n    (set t (/ t 4))\n  ))\n)\n\n(func hilbert_curve (param n int) (result (arr (vec 2 int)))\n  (let pts (arr (vec 2 int)) (alloc (arr (vec 2 int))))\n  (for d 0 (< d (* n n)) 1 (do\n    (let xy (vec 2 int) (alloc (vec 2 int)))\n    (call d2xy n d xy)\n    (insert pts (# pts) xy)\n  ))\n  (return pts)\n)\n\n(func draw_curve (param pts (arr (vec 2 int))) (param n int) (result str)\n  (local canv (arr int) (alloc (arr int)))\n  (let m int (- (* n 3) 2))\n  (for i 0 (< i (* n m)) 1 (do\n    (insert canv (# canv) ' ')\n  ))\n  (for i 1 (< i (# pts)) 1 (do\n    (let p0 (vec 2 int) (get pts (- i 1)))\n    (let p1 (vec 2 int) (get pts i))\n    (let dx int (- (get p1 0) (get p0 0)))\n    (if (= dx 0) (then\n      ; vertical line\n      (let row int (? (> (get p1 1) (get p0 1)) (get p1 1) (get p0 1) ))\n      (let col int (* (get p1 0) 3))\n      (set canv (+ (* row m) col) '|')\n    )(else\n      (let row int (get p1 1))\n      ; horizontal line\n      (let col int (? (< (get p1 0) (get p0 0)) (get p1 0) (get p0 0) ))\n      (set col (+ (* col 3) 1))\n      (set canv (+ (* row m) col  ) '_')\n      (set canv (+ (* row m) col 1) '_')\n    ))\n  ))\n  (let s str (alloc str))\n  (for i 0 (< i n) 1 (do\n    (for j 0 (< j m) 1 (do\n      (<< s (get canv (+ (* i m) j)))\n    ))\n    (<< s '\\n')\n  ))\n  (return s)\n)\n\n(func main (result int)\n  (for order 1 (<= order 5) 1 (do\n    (let n int (<< 1 order))\n    (local pts (arr (vec 2 int)) (call hilbert_curve n))\n    (local s str (call draw_curve pts n))\n    (print s) \n    (for i 0 (< i (# pts)) 1 (do\n      (free (get pts i))\n    ))\n  ))\n  (return 0)\n)","kmeans.wax":";; kmeans.wax\n;; implementation of naive kmeans algorithm\n;; in arbitrary dimensions (2d, 3d, ...)\n;; with \"random partition\" initialization\n;; https://en.wikipedia.org/wiki/K-means_clustering\n\n(@include math)\n\n;; dimensionality: 2, 3 etc.\n(@define DIM 2)\n\n\n;; datastructure for a point\n(struct pt\n\t(let pos (vec @DIM float)) ; coordinate of point\n\t(let cluster int) \n\t\t; ^ for data points, this is cluster ID\n\t\t; for cluster centers, this is number of points\n\t\t; in the cluster\n)\n\n;; square distance between two points\n(func dist_sq \n\t(param a (vec @DIM float)) \n\t(param b (vec @DIM float))\n\t(result float)\n\t\n\t(let d float 0)\n\t(for i 0 (< i @DIM) 1 (do\n\t\t(set d (+ d\n\t\t\t(call pow (- (get a i) (get b i)) 2)\n\t\t))\n\t))\n\t(return d)\n)\n\n;; free allocated data in an array of points\n(func destroy_pts (param pts (arr (struct pt)))\n\t(for i 0 (< i (# pts)) 1 (do\n\t\t(free (get pts i pos))\n\t\t(free (get pts i))\n\t))\n\t(free pts)\n)\n\n;; recompute cluster centers from the points in the cluster\n(func recomp_centers \n\t(param centers (arr (struct pt)))\n\t(param pts     (arr (struct pt)))\n\t\n\t(let n_clusters int (# centers))\n\t\n\t(for i 0 (< i n_clusters) 1 (do\n\t\t(for j 0 (< j @DIM) 1 (do\n\t\t\t(set (get centers i pos) j 0.0)\n\t\t))\n\t\t(set (get centers i) cluster 0)\n\t))\n\t(for i 0 (< i (# pts)) 1 (do\n\t\t(let c int (get pts i cluster))\n\t\t\n\t\t(for j 0 (< j @DIM) 1 (do\n\t\t\t(set (get centers c pos) j \n\t\t\t\t(+ (get centers c pos j) (get pts i pos j))\n\t\t\t)\n\t\t))\n\t\t(set (get centers c) cluster\n\t\t\t(+ (get centers c cluster) 1)\n\t\t)\n\t))\n\t(for i 0 (< i n_clusters) 1 (do\n\t\t(if (get centers i cluster) (then\n\t\t\t(for j 0 (< j @DIM) 1 (do\n\t\t\t\t(set (get centers i pos) j \n\t\t\t\t\t(/ (get centers i pos j) (get centers i cluster))\n\t\t\t\t)\n\t\t\t))\n\t\t))\n\t))\n)\n\n;; run kmeans algirthm\n(func kmeans \n\t(param pts (arr (struct pt))) \n\t(param n_clusters int)\n\t(param max_iter int)\n\t\n\t; assign each point to a random cluster\n\t(for i 0 (< i (# pts)) 1 (do\n\t\t(set (get pts i) cluster \n\t\t\t(cast (* (call random) n_clusters) int)\n\t\t)\n\t))\n\t\n\t; initialize the cluster centers\n\t(let centers (arr (struct pt)) (alloc (arr (struct pt))))\n\t\n\t(for i 0 (< i n_clusters) 1 (do\n\t\t(let p (struct pt) (alloc (struct pt)))\n\t\t(set p pos (alloc (vec @DIM float)))\n\t\t(insert centers (# centers) p)\n\t))\n\t\n\t; run kmeans iteration\n\t(for iter 0 (< iter max_iter) 1 (do\n\t\t\n\t\t(call recomp_centers centers pts)\n\t\t\n\t\t(let diff int 0) ; anything changed? nothing->done\n\t\t\n\t\t; find closest cluster center to attach the point\n\t\t(for i 0 (< i (# pts)) 1 (do\n\t\t\t(let dstmin float INFINITY)\n\t\t\t(let argmin int 0) \n\t\t\t(for j 0 (< j n_clusters) 1 (do\n\t\t\t\t(let d float (call dist_sq\n\t\t\t\t\t(get pts     i pos)\n\t\t\t\t\t(get centers j pos)\n\t\t\t\t))\n\t\t\t\t(if (< d dstmin) (then\n\t\t\t\t\t(set dstmin d)\n\t\t\t\t\t(set argmin j)\n\t\t\t\t))\n\t\t\t\n\t\t\t))\n\t\t\t(if (<> argmin (get pts i cluster)) (then\n\t\t\t\t(set diff 1)\n\t\t\t))\n\t\t\t(set (get pts i) cluster argmin)\n\t\t))\n\t\t\n\t\t(if (! diff) (then ; no change, done!\n\t\t\t(break)\n\t\t))\n\t))\n\t\n\t(call destroy_pts centers)\n\t\n)\n\n\n;; end of kmeans algorithm\n;;=================================================================\n;; start of testing kmeans\n\n\n\n;; parameters for testing\n(@define RANGE   50  ) ; range of random coordinates\n(@define RANGESQ 2500) ; range^2\n\n;; plot result of kmeans via ASCII art\n;; only the first two dimensions are plotted (x,y)\n;; higher dimensions are ignored\n(func plot2d (param pts (arr (struct pt)))\n\t(local pix \n\t\t(vec @RANGESQ int) \n\t\t(alloc (vec @RANGESQ int))\n\t)\n\t(for i 0 (< i (# pts)) 1 (do\n\t\t(let x int (get pts i pos 0))\n\t\t(let y int (get pts i pos 1))\n\t\t(set pix (+ (* y @RANGE) x) \n\t\t\t(+ (get pts i cluster) 1)\n\t\t)\n\t))\n\t(local s str (alloc str))\n\t(for i 0 (< i @RANGESQ) 1 (do\n\t\t(if (! (% i @RANGE)) (then\n\t\t\t(<< s \"\\n\")\n\t\t))\n\t\t(<< s (+ (get pix i) 32))\n\t))\n\t(print s)\n)\n\n\n;; generate a bunch of random points\n;; run kmeans, and plot the output in terminal\n(func main (result int)\n\t(let pts (arr (struct pt)) (alloc (arr (struct pt))))\n\n\t; populate points with random coordinates\t\n\t(for i 0 (< i 200) 1 (do\n\t\t(let p (struct pt) (alloc (struct pt)))\n\t\t(set p pos (alloc (vec @DIM float)))\n\t\t\n\t\t(for j 0 (< j @DIM) 1 (do\n\t\t\t(set (get p pos) j (* (call random) @RANGE))\n\t\t))\n\t\t(insert pts (# pts) p)\n\t\t\n\t))\n\t\n\t(call kmeans pts 6 300)\n\t\n\t(call plot2d pts)\n\t\n\t(call destroy_pts pts)\n\t(return 0)\n)\n","line.wax":";; line.wax\n;; rasterize lines using simple line algorithm\n\n(@include math)\n\n;; datastructure for storing an image\n(struct image\n\t(let data (arr int))\n\t(let w int) ; width\n\t(let h int) ; height\n)\n\n;; initialize an image full of zeros\n(func zeros (param w int) (param h int) \n\t(result (struct image))\n\t\n\t(let data (arr int) (alloc (arr int)))\n\t(let im (struct image) (alloc (struct image)))\n\t(for i 0 (< i (* w h)) 1 (do\n\t\t(insert data (# data) 0)\n\t))\n\t(set im data data)\n\t(set im w w)\n\t(set im h h)\n\t(return im)\n)\n\n;; read value of a pixel\n(func getpixel \n\t(param im (struct image))\n\t(param x int) (param y int)\n\t(result int)\n\t(if (||   ; boundary check\n\t\t(<  x 0) (< y 0)\n\t\t(>= x (get im w))\n\t\t(>= y (get im h))\n\t)(then\n\t\t(return 0)\n\t))\n\t(return \n\t\t(get im data (+ (* y (get im w)) x))\n\t)\n)\n\n;; write value to a pixel\n(func setpixel \n\t(param im (struct image))\n\t(param x int) (param y int) (param v int)\n\t(if (||   ; boundary check\n\t\t(<  x 0) (< y 0)\n\t\t(>= x (get im w))\n\t\t(>= y (get im h))\n\t)(then\n\t\t(return)\n\t))\n\t(set (get im data)\n\t\t(+ (* y (get im w)) x)\n\t\tv\n\t)\n)\n\n;; helper for line drawing algorithm\n;; compute x/y from y/x using slope\n(func linestep\n\t(param sx0 int) (param sx1 int)\n\t(param sy0 int) (param sy1 int)\n\t(param x int)\n\t(result int)\n\t(if (= sx0 sx1) (then\n\t\t(return sy1)\n\t))\n\t(return (cast (call round\n\t\t(+ sy0 (*\n\t\t\t(- x sx0)\n\t\t\t(/ (- sy1 sy0) (cast (- sx1 sx0) float) )\n\t\t))\n\t) int))\n)\n\n;; raster line drawing algorithm\n(func line \n\t(param im (struct image))\n\t(param x0 float) (param y0 float) ; start pos\n\t(param x1 float) (param y1 float) ; end pos\n\t(param v int) ;color\n\t \n\t(let sx0 int (call round x0))\n\t(let sy0 int (call round y0))\n\t(let sx1 int (call round x1))\n\t(let sy1 int (call round y1))\n\t\n\t(let dx int (? (> sx1 sx0) 1 -1)) ; x increment\n\t(let dy int (? (> sy1 sy0) 1 -1)) ; y increment\n\t\n\t(if (>=\n\t\t(call abs (- sx0 sx1))\n\t\t(call abs (- sy0 sy1))\n\t)(then ; slope < 1 ?\n\t\t(let x int sx0)\n\t\t(while (<> x (+ sx1 dx)) (do\n\t\t\t(let y int (call linestep sx0 sx1 sy0 sy1 x))\n\t\t\t(call setpixel im x y v)\n\t\t\t(set x (+ x dx))\n\t\t))\n\t)(else\n\t\t(let y int sy0)\n\t\t(while (<> y (+ sy1 dy)) (do\n\t\t\t(let x int (call linestep sy0 sy1 sx0 sx1 y))\n\t\t\t(call setpixel im x y v)\n\t\t\t(set y (+ y dy))\n\t\t))\n\t))\n)\n\n;; visualize the image with ASCII drawing in terminal\n(func imshow (param im (struct image))\n\t(local s str (alloc str \"+\"))\n\t(for j 0 (< j (get im w)) 1 (do (<< s \"-\")))\n\t(<< s \"+\\n\")\n\t(for i 0 (< i (get im h)) 1 (do\n\t\t(<< s \"|\")\n\t\t(for j 0 (< j (get im w)) 1 (do\n\t\t\t(<< s (+ (call getpixel im j i) 32))\n\t\t))\n\t\t(<< s \"|\\n\")\n\t))\n\t(<< s \"+\")\n\t(for j 0 (< j (get im w)) 1 (do (<< s \"-\")))\n\t(<< s \"+\")\n\t(print s)\n)\n\n;; free allocated image\n(func dispose (param im (struct image))\n\t(free (get im data))\n\t(free im)\n)\n\n(func main (result int)\n\t(let im (struct image) (call zeros 60 30))\n\t\n\t;; generate some random lines to draw\n\t(for i 0 (< i 7) 1 (do\n\t\t(let x0 float (* (call random) (get im w)))\n\t\t(let y0 float (* (call random) (get im h)))\n\t\t(let x1 float (* (call random) (get im w)))\n\t\t(let y1 float (* (call random) (get im h)))\n\t\t(let v int (+ i 1))\n\t\t(call line im x0 y0 x1 y1 v)\n\t))\n\t\n\t(call imshow im)\n\t(call dispose im)\n\t(return 0)\n)\n","nqueens.wax":";; N-Queens Problem Solver\n;; ported from\n;; http://www.rosettacode.org/wiki/N-queens_problem#Java\n\n\n(@define N 8) ; board size / # of queens\n\n; check if a position is unsafe (attackable)\n(func attackable \n\t(param B (vec @N int)) \n\t(param y int)\n\t(result int)\n\t\n\t(let x int (get B y))\n\t(for i 1 (<= i y) 1 (do\n\t\t(let t int (get B (- y i)))\n\t\t(if (||\n\t\t\t(= t x) \n\t\t\t(= t (- x i))\n\t\t\t(= t (+ x i))) (then\n\t\t\t(return 1)\t\n\t\t))\n\t))\n\t(return 0)\n)\n\n; visualize a solution \n; by printing ASCCi chessboard in terminal\n(func putboard (param B (vec @N int)) (param s int)\n\t(local o str (alloc str \"N=\"))\n\t(<< o (cast @N str))\n\t(<< o \" solution #\")\n\t(<< o (cast s str))\n\t(<< o \"\\n\")\n\t(for y 0 (< y @N) 1 (do\n\t\t(for x 0 (< x @N) 1 (do\n\t\t\t(<< o\n\t\t\t\t(? (= (get B y) x) \"|Q\" \"|_\")\n\t\t\t)\n\t\t))\n\t\t(<< o \"|\\n\")\n\t))\n\t(print o)\n)\n\n; solve N-Queens puzzle (exhaustive)\n(func solve\n\t(local B (vec @N int) (alloc (vec @N int))) ; chessboard\n\t(let s int 0)  ; solution ID\n\t(let y int 0)  ; current row\n\t(set B 0 -1)\n\t\n\t(while (>= y 0) (do\n\t\t(set B y (+ (get B y) 1))\n\t\t(while (&&\n\t\t\t(< (get B y) @N)\n\t\t\t(call attackable B y)\n\t\t)(do\n\t\t\t(set B y (+ (get B y) 1))\n\t\t))\n\t\t(if (< (get B y) @N) (then\n\t\t\t(if (< y (- @N 1)) (then\n\t\t\t\t(set y (+ y 1))\n\t\t\t\t(set B y -1)\n\t\t\t)(else\n\t\t\t\t(set s (+ s 1))\n\t\t\t\t(call putboard B s)\n\t\t\t))\n\t\t)(else\n\t\t\t(set y (- y 1))\n\t\t))\n\t))\n)\n\n(func main (result int)\n\t(call solve)\n\t(return 0)\n)","poissondisk.wax":";; Poisson-Disk sampling\n;; Based on paper:\n;; https://www.cs.ubc.ca/~rbridson/docs/bridson-siggraph07-poissondisk.pdf\n;; and Daniel Shiffman's p5.js implementation:\n;; https://editor.p5js.org/codingtrain/sketches/4N78DFCXN\n\n(@include math)\n\n(@define K 30) ; \"the limit of samples to choose before rejection in the algorithm\"\n\n;; distance square\n(func dist2 (param x0 float) (param y0 float) (param x1 float) (param y1 float) (result float)\n\t(let dx float (- x0 x1))\n\t(let dy float (- y0 y1))\n\t(return (+ (* dx dx) (* dy dy)))\n)\n\n(func poissondisk\n\t(param W int) (param H int)         ; width, height\n\t(param r float)                     ; radius\n\t(param samples (arr (vec 2 float))) ; to be populated; can also be pre-filled with fixed points\n\n\t(local grid (arr int) (alloc (arr int)))\n\t(local active (arr (vec 2 float)) (alloc (arr (vec 2 float))))\n\n\t(let w float (/ r 1.4142135624))\n\t(let r2 float (* r r))\n\t(let cols int (/ W w))\n\t(let rows int (/ H w))\n\t\n\t(for i 0 (< i (* cols rows)) 1 (do\n\t\t(insert grid (# grid) -1)\n\t))\n\t(let pos (vec 2 float) (alloc (vec 2 float) \n\t\t(/ W 2.0)\n\t\t(/ H 2.0)\n\t))\n\t(insert samples (# samples) pos)\n\t(for i 0 (< i (# samples)) 1 (do\n\t\t(let col int (/ (get samples i 0) w))\n\t\t(let row int (/ (get samples i 1) w))\n\t\t(set grid (+ col (* row cols)) i)\n\t\t(insert active (# active) (get samples i))\n\t))\n\n\t(while (# active) (do\n\t\t(let ridx int (* (call random) (# active)) )\n\t\t(set pos (get active ridx))\n\t\t(let found int 0)\n\t\t(for n 0 (< n @K) 1 (do\n\t\t\t(let sr float (+ r (* (call random) r)) )\n\t\t\t(let sa float (* 6.2831853072 (call random)))\n\t\t\t(let sx float (+ (get pos 0) (* sr (call cos sa))))\n\t\t\t(let sy float (+ (get pos 1) (* sr (call sin sa))))\n\t\t\t(let col int (/ sx w))\n\t\t\t(let row int (/ sy w))\n\t\t\t(if (&&\n\t\t\t\t(> col 0)\n\t\t\t\t(> row 0)\n\t\t\t\t(< col (- cols 1))\n\t\t\t\t(< row (- rows 1))\n\t\t\t\t(= (get grid (+ col (* row cols))) -1)\n\t\t\t)(then\n\t\t\t\t(let ok int 1)\n\t\t\t\t(for i -1 (<= i 1) 1 (do\n\t\t\t\t\t(for j -1 (<= j 1) 1 (do\n\t\t\t\t\t\t(let idx int (+ (* (+ row i) cols) col j))\n\t\t\t\t\t\t(let nbr int (get grid idx))\n\t\t\t\t\t\t(if (<> -1 nbr) (then\n\t\t\t\t\t\t\t(let d float (call dist2 sx sy (get samples nbr 0) (get samples nbr 1)) )\n\t\t\t\t\t\t\t(if (< d r2) (then\n\t\t\t\t\t\t\t\t(set ok 0)\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t))\n\t\t\t\t\t))\n\t\t\t\t))\n\t\t\t\t(if ok (then\n\t\t\t\t\t(set found 1)\n\t\t\t\t\t(set grid (+ (* row cols) col) (# samples))\n\t\t\t\t\t(let sample (vec 2 float) (alloc (vec 2 float) sx sy))\n\t\t\t\t\t(insert active (# active) sample)\n\t\t\t\t\t(insert samples (# samples) sample)\n\t\t\t\t))\n\t\t\t))\n\t\t))\n\t\t(if (! found) (then\n\t\t\t(remove active ridx 1)\n\t\t))\n\t))\n\n)\n\n;; draw sample points to svg image\n(func plotsamples (param W int) (param H int) \n\t(param samples (arr (vec 2 float)))\n\t(result str)\n\t(let s str (alloc str \"<svg version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" width=\\\"\"))\n\t(<< s (cast W str))\n\t(<< s \"\\\" height=\\\"\")\n\t(<< s (cast H str))\n\t(<< s \"\\\">\")\n\n\t(for i 0 (< i (# samples)) 1 (do\n\t\t(<< s \"<circle cx=\\\"\")\n\t\t(<< s (cast (get samples i 0) str))\n\t\t(<< s \"\\\" cy=\\\"\")\n\t\t(<< s (cast (get samples i 1) str))\n\t\t(<< s \"\\\" r=\\\"1\\\" fill=\\\"hsl(\")\n\t\t(<< s (cast (/ i 5) str))\n\t\t(<< s \",100%,30%)\\\"/>\")\n\t))\n\n\t(<< s \"</svg>\")\n\t(return s)\n\n)\n\n;; test poisson disk\n(func main (result int)\n\t(let W int 400)\n\t(let H int 400)\n\t(let r int 4)\n\t(local samples (arr (vec 2 float)) (alloc (arr (vec 2 float))) )\n\t(call poissondisk W H r samples)\n\t(local s str (call plotsamples W H samples))\n\t(print s)\n\t(for i 0 (< i (# samples)) 1 (do\n\t\t(free (get samples i))\n\t))\n\t(return 0)\n)","quicksort.wax":";; \"Quicksort\"\n;; includes both an in-place implementation\n;; and a functional implementation\n\n\n;; sort array in-place for index range [lo,hi] inclusive\n(func qksort_inplace (param A (arr float)) (param lo int) (param hi int)\n\t(if (>= lo hi) (then\n\t\t(return)\n\t))\n\t(let pivot float (get A lo))\n\t(let left  int lo)\n\t(let right int hi)\n\t(while (<= left right) (do\n\t\t(while (< (get A left) pivot) (do\n\t\t\t(set left (+ left 1))\n\t\t))\n\t\t(while (> (get A right) pivot) (do\n\t\t\t(set right (- right 1))\n\t\t))\n\t\t(if (<= left right) (then\n\t\t\t(let tmp float (get A left))\n\t\t\t(set A left (get A right))\n\t\t\t(set A right tmp)\n\t\t\t(set left  (+ left 1))\n\t\t\t(set right (- right 1))\n\t\t))\n\t))\n\t(call qksort_inplace A lo right)\n\t(call qksort_inplace A left hi)\n)\n\n;; wrap qksort_inplace\n(func qksort (param A (arr float))\n\t(if (! (# A)) (then\n\t\t(return)\n\t))\n\t(call qksort_inplace A 0 (- (# A) 1))\n)\n\n;; functional version of quicksort\n(func qksort_func (param A (arr float)) (result (arr float))\n\t(if (<= (# A) 1) (then\n\t\t(return (slice A 0 (# A)))\n\t))\n\t(let pivot float (get A 0))\n\t(local less (arr float) (alloc (arr float)))\n\t(local more (arr float) (alloc (arr float)))\n\t(for i 1 (< i (# A)) 1 (do\n\t\t(if (< (get A i) pivot) (then\n\t\t\t(insert less (# less) (get A i))\n\t\t)(else\n\t\t\t(insert more (# more) (get A i))\n\t\t))\n\t))\n\t(let  sorted (arr float) (call qksort_func less))\n\t(local right (arr float) (call qksort_func more))\n\t(insert sorted (# sorted) pivot)\n\t(for i 0 (< i (# right)) 1 (do\n\t\t(insert sorted (# sorted) (get right i))\n\t))\n\t(return sorted)\n)\n\n;; print an array separated by commas\n(func print_arr (param A (arr float))\n\t(local s str (alloc str \"\"))\n\t(for i 0 (< i (# A)) 1 (do\n\t\t(if i (then (<< s \", \")))\n\t\t(<< s (cast (get A i) str))\n\t))\n\t(print s)\n)\n\n(func main (result int)\n\n\t(local A (arr float) (alloc (arr float) \n\t\t0.9 0.2 88 10 3 4 5.5 0.1\n\t))\n\n\t(print \"original array:\")\n\t(call print_arr A)\n\t\n\t(local B (arr float) (call qksort_func A))\n\n\t(print \"sorted with functional quicksort:\")\n\t(call print_arr B)\n\n\t(print \"original array is unchanged:\")\n\t(call print_arr A)\n\n\t(call qksort A)\n\n\t(print \"sorted with in-place quicksort:\")\n\t(call print_arr A)\n\t\n\t(return 0)\n)\n","quine.wax":";; quine.wax\n;; based on https://en.wikipedia.org/wiki/Quine_(computing)\n(func main (result int)\n  (let q int 34)\n  (local s str (alloc str))\n  (local l (arr str) (alloc (arr str) \n  \";; quine.wax\"\n  \";; based on https://en.wikipedia.org/wiki/Quine_(computing)\"\n  \"(func main (result int)\"\n  \"  (let q int 34)\"\n  \"  (local s str (alloc str))\"\n  \"  (local l (arr str) (alloc (arr str)\"\n  \"  \"\n  \"  ))\"\n  \"  (for i 0 (< i 6) 1 (do\"\n  \"    (<< s (get l i)) (<< s 10)\"\n  \"  ))\"\n  \"  (for i 0 (< i (# l)) 1 (do\"\n  \"    (<< s (get l 6))\"\n  \"    (<< s q) (<< s (get l i)) (<< s q) (<< s 10)\"\n  \"  ))\"\n  \"  (for i 7 (< i (# l)) l (do\"\n  \"    (<< s (get l i)) (<< s 10)\"\n  \"  ))\"\n  \"  (print s)\"\n  \"  (return 0)\"\n  \")\"\n  ))\n  (for i 0 (< i 6) 1 (do\n    (<< s (get l i)) (<< s 10)\n  ))\n  (for i 0 (< i (# l)) 1 (do\n    (<< s (get l 6))\n    (<< s q) (<< s (get l i)) (<< s q) (<< s 10)\n  ))\n  (for i 7 (< i (# l)) 1 (do\n    (<< s (get l i)) (<< s 10)\n  ))\n  (print s)\n  (return 0)\n)","raycast.wax":";; raycast.wax\n;; bare-minimum raycaster demo\n;;\n;; - ray-triangle intersection\n;; - \"n-dot-l\" shading\n;; - face normals only\n;; - no trees/partitioning for acceleration\n;; - includes a dodecahedron example\n;; - ascii art for plotting renders\n\n(@include math)\n\n;; dimension of camera\n(@define W      80)\n(@define H      40)\n(@define WxH  3840)\n(@define FOCAL 100)\n\n;; datastructure for a ray\n(struct ray\n\t(let o (vec 3 float)) ; origin\n\t(let d (vec 3 float)) ; direction\n\t(let tmin float)      ; t parameter extremas\n\t(let tmax float)\n)\n\n;; datastructure for a mesh\n(struct mesh\n\t(let vertices  (arr (vec 3 float)))  ; 3d coordinates\n\t(let faces     (arr (vec 3 int  )))  ; winding\n\t(let facenorms (arr (vec 3 float)))\n)\n\n;; ========== vector math utilities ========== \n\n;; subtract\n(func v_sub \n\t(param u (vec 3 float))\n\t(param v (vec 3 float))\n\t(result  (vec 3 float))\n\n\t(return (alloc (vec 3 float)\n\t\t(- (get u 0) (get v 0))\n\t\t(- (get u 1) (get v 1))\n\t\t(- (get u 2) (get v 2))\n\t))\n)\n\n;; cross product\n(func v_cross\n\t(param u (vec 3 float))\n\t(param v (vec 3 float))\n\t(result  (vec 3 float))\n\t(return (alloc (vec 3 float)\n\t\t(-\n\t\t\t(* (get u 1) (get v 2))\n\t\t\t(* (get u 2) (get v 1))\n\t\t)(-\n\t\t\t(* (get u 2) (get v 0))\n\t\t\t(* (get u 0) (get v 2))\n\t\t)(-\n\t\t\t(* (get u 0) (get v 1))\n\t\t\t(* (get u 1) (get v 0))\n\t\t)\n\t))\n)\n\n;; dot product\n(func v_dot\n\t(param u (vec 3 float))\n\t(param v (vec 3 float))\n\t(result float)\n\n\t(return (+\n\t\t(* (get u 0) (get v 0))\n\t\t(* (get u 1) (get v 1))\n\t\t(* (get u 2) (get v 2))\n\t))\n)\n\n;; resize by a scalar\n(func v_scale\n\t(param u (vec 3 float))\n\t(param x float)\n\t(result (vec 3 float))\n\t\n\t(return (alloc (vec 3 float)\n\t\t(* (get u 0) x)\n\t\t(* (get u 1) x)\n\t\t(* (get u 2) x)\n\t))\n)\n\n;; magnitude (euclidean norm)\n(func v_mag\n\t(param v (vec 3 float))\n\t(result float)\n\t\n\t(return (call sqrt\n\t\t(+\n\t\t\t(* (get v 0) (get v 0))\n\t\t\t(* (get v 1) (get v 1))\n\t\t\t(* (get v 2) (get v 2))\n\t\t)\n\t))\n)\n\n;; normalize to unit vector *in-place*\n(func normalize\n\t(param v (vec 3 float))\n\t\n\t(let l float (call v_mag v))\n\t(set v 0 (/ (get v 0) l))\n\t(set v 1 (/ (get v 1) l))\n\t(set v 2 (/ (get v 2) l))\n)\n\n;; determinant\n(func det\n\t(param a (vec 3 float))\n\t(param b (vec 3 float))\n\t(param c (vec 3 float))\n\t(result float)\n\n\t(local d (vec 3 float) (call v_cross a b))\n\t(let e float (call v_dot d c))\n\t(return e)\n)\n\n;; ========== ray calculations ========== \n\n;; create new ray\n(func new_ray\n\t(param ox float) (param oy float) (param oz float)\n\t(param dx float) (param dy float) (param dz float)\n\t(result (struct ray))\n\t\n\t(let r (struct ray)  (alloc (struct ray)))\n\t(let o (vec 3 float) (alloc (vec 3 float)\n\t\tox oy oz\n\t))\n\t(let d (vec 3 float) (alloc (vec 3 float)\n\t\tdx dy dz\n\t))\n\t(call normalize d)\n\t(set r o o)\n\t(set r d d)\n\t(set r tmin 0.0)\n\t(set r tmax INFINITY)\n\t(return r)\n)\n\n;; free allocated ray\n(func destroy_ray\n\t(param r (struct ray))\n\t(free (get r o))\n\t(free (get r d))\n\t(free r)\n)\n\n;; ray-triangle intersection\n(func ray_tri\n\t(param r  (struct ray) )\n\t(param p0 (vec 3 float)) \n\t(param p1 (vec 3 float))\n\t(param p2 (vec 3 float))\n\t(result float)\n\n\t(local e1 (vec 3 float) (call v_sub p1 p0))\n\t(local e2 (vec 3 float) (call v_sub p2 p0))\n\t\n\t(local s  (vec 3 float) (call v_sub   (get r o) p0))\n\t(local _d (vec 3 float) (call v_scale (get r d) -1))\n\t\n\t(let denom float (call det e1 e2 _d))\n\t\n\t(if (= denom 0) (then\n\t\t(return INFINITY)\n\t))\n\t\n\t(let u float (/ (call det s e2 _d) denom))\n\t(let v float (/ (call det e1 s _d) denom))\n\t(let t float (/ (call det e1 e2 s) denom))\n\t\n\t\n\t(if (||\n\t\t(< u 0) (< v 0)\n\t\t(< (- 1 (+ u v)) 0)\n\t\t(< t (get r tmin)) (> t (get r tmax))) (then\n\n\t\t(return INFINITY)\t\n\t))\n\t\n\t(set r tmax t)\n\t(return t)\n)\n\n;; ray-mesh intersection\n;; naive triangle-by-triangle checking \n;; -- for better speed, replace with BVH, k-d tree etc.\n(func ray_mesh\n\t(param r (struct ray ))\n\t(param m (struct mesh))\n\t(param l (vec 3 float))\n\t(result float)\n\n\t(let dstmin float INFINITY)\n\t(let argmin int -1)\n\t(for i 0 (< i (# (get m faces))) 1 (do\n\t\t(let a (vec 3 float) (get m vertices (get m faces i 0)))\n\t\t(let b (vec 3 float) (get m vertices (get m faces i 1)))\n\t\t(let c (vec 3 float) (get m vertices (get m faces i 2)))\n\t\t(let t float (call ray_tri r a b c))\n\t\t(if (< t dstmin) (then\n\t\t\t(set dstmin t)\n\t\t\t(set argmin i)\n\t\t))\n\t))\n\t(if (|| (< argmin -1) (= dstmin INFINITY)) (then\n\t\t(return 0.0)\n\t))\n\t\n\t(let n  (vec 3 float) (get m facenorms argmin))\n\n\t(let ndotl float (call v_dot n l))\n\t(return (+ (call fmax ndotl 0) 0.1))\n)\n\n;; ========== mesh calculations ========== \n\n;; add vertex to mesh\n(func add_vert\n\t(param m (struct mesh))\n\t(param x float)\n\t(param y float)\n\t(param z float)\n\t\n\t(insert (get m vertices) (# (get m vertices))\n\t\t(alloc (vec 3 float) x y z)\n\t)\n)\n\n;; add face to mesh\n(func add_face\n\t(param m (struct mesh))\n\t(param a int)\n\t(param b int)\n\t(param c int)\n\t\n\t(insert (get m faces) (# (get m faces))\n\t\t; hacks specific to .obj files:\n\t\t; -1 because in .obj format index starts at 1\n\t\t; (a,c,b) because some .obj's wind the wrong way\n\t\t(alloc (vec 3 int) (- a 1) (- c 1) (- b 1))\n\t)\n)\n\n;; pre-compute the face normals\n(func calc_facenorms (param m (struct mesh))\n\t(for i 0 (< i (# (get m faces))) 1 (do\n\t\t(let a (vec 3 float) (get m vertices (get m faces i 0)))\n\t\t(let b (vec 3 float) (get m vertices (get m faces i 1)))\n\t\t(let c (vec 3 float) (get m vertices (get m faces i 2)))\n\t\t\n\t\t(local e1 (vec 3 float) (call v_sub a b))\n\t\t(local e2 (vec 3 float) (call v_sub b c))\n\n\t\t(let n  (vec 3 float) (call v_cross e1 e2))\n\t\t(call normalize n)\n\t\t(insert (get m facenorms) (# (get m facenorms)) n)\n\t))\n)\n\n;; translate mesh\n(func move_mesh \n\t(param m (struct mesh)) \n\t(param x float) (param y float) (param z float)\n\t(for i 0 (< i (# (get m vertices))) 1 (do\n\t\t(set (get m vertices i) 0 (+ (get m vertices i 0) x))\n\t\t(set (get m vertices i) 1 (+ (get m vertices i 1) y))\n\t\t(set (get m vertices i) 2 (+ (get m vertices i 2) z))\n\t))\n)\n\n;; free allocated mesh\n(func destroy_mesh\n\t(param m (struct mesh))\n\t(for i 0 (< i (# (get m vertices))) 1 (do\n\t\t(free (get m vertices i))\n\t))\n\t(free (get m vertices))\n\t(for i 0 (< i (# (get m faces))) 1 (do\n\t\t(free (get m faces i))\n\t))\n\t(free (get m faces))\n\t(for i 0 (< i (# (get m facenorms))) 1 (do\n\t\t(free (get m facenorms i))\n\t))\n\t(free (get m facenorms))\n\t(free m)\n)\n\n;; render a mesh and print ASCII art\n(func render (param m (struct mesh)) (param light (vec 3 float))\n\t(local pix (vec @WxH float) (alloc (vec @WxH float)))\n\t\n\t(call normalize light)\n\t\n\t(let palette str \"`.-,_:^!~;r+|()=>l?icv[]tzj7*f{}sYTJ1unyIFowe2h3Za4X%5P$mGAUbpK960#H&DRQ80WMB@N\")\n\t(let lo float INFINITY)\n\t(let hi float 0)\n\t(for y 0 (< y @H) 1 (do\n\t\t(for x 0 (< x @W) 1 (do\n\t\t\t(let fx float (/ (- x (/ @W 2.0)) 2.0 ))\n\t\t\t(let fy float (- y (/ @H 2.0)))\n\t\t\t(let r (struct ray) \n\t\t\t\t(call new_ray 0 0 0 fx fy @FOCAL)\n\t\t\t)\n\t\t\t(let gray float (call ray_mesh r m light))\n\t\t\t(set hi (call fmax gray hi))\n\t\t\t(if (> gray 0) (then\n\t\t\t\t(set lo (call fmin gray lo))\n\t\t\t))\n\t\t\t(set pix (+ (* y @W) x) gray)\n\t\t\t(call destroy_ray r)\n\t\t))\n\t))\n\t\n\t(local s str (alloc str))\n\t(for y 0 (< y @H) 1 (do\n\t\t(for x 0 (< x @W) 1 (do\n\t\t\t(let gray float (get pix (+ (* y @W) x)))\n\t\t\t(if (<> gray 0) (then\n\t\t\t\t(set gray (/ (- gray lo) (- hi lo) ))\n\t\t\t\t(let ch int (get palette (cast (* gray 78) int)))\n\t\t\t\t(<< s ch)\n\t\t\t)(else\n\t\t\t\t(<< s ' ')\n\t\t\t))\n\t\t\t\n\t\t))\n\t\t(<< s \"\\n\")\n\t))\n\t(print s)\n)\n\n\n;; ========== testing code ========== \n\n;; the dodecahedron, a platonic solid, hard-coded by re-formatting an .obj file\n(func dodecahedron\n\t(result (struct mesh))\n\t\n\t(let m (struct mesh) (alloc (struct mesh)))\n\t(set m vertices      (alloc (arr (vec 3 float))))\n\t(set m faces         (alloc (arr (vec 3 int))))\n\t(set m facenorms     (alloc (arr (vec 3 float))))\n\t\t\n\t(call add_vert m -0.436466 -0.668835 0.601794)\n\t(call add_vert m 0.918378 0.351401 -0.181931)\n\t(call add_vert m 0.886304 -0.351401 -0.301632)\n\t(call add_vert m -0.886304 0.351401 0.301632)\n\t(call add_vert m -0.918378 -0.351401 0.181931)\n\t(call add_vert m 0.132934 0.858018 0.496117)\n\t(call add_vert m -0.048964 0.981941 -0.182738)\n\t(call add_vert m 0.106555 0.162217 -0.980985)\n\t(call add_vert m -0.582772 0.162217 -0.796280)\n\t(call add_vert m -0.132934 -0.858018 -0.496117)\n\t(call add_vert m 0.048964 -0.981941 0.182738)\n\t(call add_vert m 0.582772 -0.162217 0.796280)\n\t(call add_vert m -0.106555 -0.162217 0.980985)\n\t(call add_vert m 0.436466 0.668835 -0.601794)\n\t(call add_vert m 0.730785 0.468323 0.496615)\n\t(call add_vert m -0.678888 0.668835 -0.302936)\n\t(call add_vert m -0.384570 0.468323 0.795474)\n\t(call add_vert m 0.384570 -0.468323 -0.795474)\n\t(call add_vert m 0.678888 -0.668835 0.302936)\n\t(call add_vert m -0.730785 -0.468323 -0.496615)\n\n\t(call add_face m 19  3  2)  (call add_face m 12  19  2) (call add_face m 15  12  2) \n\t(call add_face m 8  14  2)  (call add_face m 18  8  2)  (call add_face m 3  18  2)\n\t(call add_face m 20  5  4)  (call add_face m 9  20  4)  (call add_face m 16  9  4)  \n\t(call add_face m 13  17  4) (call add_face m 1  13  4)  (call add_face m 5  1  4)\n\t(call add_face m 7  16  4)  (call add_face m 6  7  4)   (call add_face m 17  6  4)  \n\t(call add_face m 6  15  2)  (call add_face m 7  6  2)   (call add_face m 14  7  2)\n\t(call add_face m 10  18  3) (call add_face m 11  10  3) (call add_face m 19  11  3) \n\t(call add_face m 11  1  5)  (call add_face m 10  11  5) (call add_face m 20  10  5)\n\t(call add_face m 20  9  8)  (call add_face m 10  20  8) (call add_face m 18  10  8) \n\t(call add_face m 9  16  7)  (call add_face m 8  9  7)   (call add_face m 14  8  7)\n\t(call add_face m 12  15  6) (call add_face m 13  12  6) (call add_face m 17  13  6) \n\t(call add_face m 13  1  11) (call add_face m 12  13  11)(call add_face m 19  12  11)\n\n\t(call calc_facenorms m)\n\n\t(return m)\n)\n\n;; test the ray caster\n(func main (result int)\n\t(let m (struct mesh) (call dodecahedron))\n\t(call move_mesh m 0 0 5)\n\t\n\t(local light (vec 3 float) (alloc (vec 3 float) 0.1 0.2 0.4))\n\t(call render m light)\n\n\t(call destroy_mesh m)\n\t(return 0)\n)\n\n","traceskeleton.wax":";; traceskeleton.wax\n;; Trace skeletonization result into polylines\n;;\n;; see https://github.com/LingDong-/skeleton-tracing\n;; ported to wax to illustrate a real-world usage\n;; with original comments\n\n(@include math)\n\n(@define HORIZONTAL 1)\n(@define VERTICAL   2)\n\n(let CHUNK_SIZE int 10)\n\n;;================================\n;; DATASTRUCTURES\n;;================================\n\n(struct point\n\t(let x int)\n\t(let y int)\n\t(let next (struct point))\n)\n(struct polyline\n\t(let head (struct point))\n\t(let tail (struct point))\n\t(let prev (struct polyline))\n\t(let next (struct polyline))\n\t(let size int)\n)\n\n;;================================\n;; DATASTRUCTURE IMPLEMENTATION\n;;================================\n\n(func new_polyline (result (struct polyline))\n\t(let q0 (struct polyline) (alloc (struct polyline)))\n\t(return q0)\n)\n(func print_polyline (param q (struct polyline))\n\t(if (! (?? q)) (then\n\t\t(return)\n\t))\n\t(let jt (struct point) (get q head))\n\t(local s str (alloc str))\n\t(while (?? jt) (do\n\t\t(<< s (cast (get jt x) str))\n\t\t(<< s \",\")\n\t\t(<< s (cast (get jt y) str))\n\t\t(<< s \" \")\n\t\t(set jt (get jt next))\n\t))\n\t(print s)\n)\n(func print_polylines (param q (struct polyline))\n\t(if (! (?? q)) (then\n\t\t(return)\n\t))\n\t(let it (struct polyline) q)\n\t(while (?? it) (do\n\t\t(let jt (struct point) (get it head))\n\t\t(local s str (alloc str))\n\t\t(while (?? jt) (do\n\t\t\t(<< s (cast (get jt x) str))\n\t\t\t(<< s \",\")\n\t\t\t(<< s (cast (get jt y) str))\n\t\t\t(<< s \" \")\n\t\t\t(set jt (get jt next))\n\t\t))\n\t\t(print s)\n\t\t(set it (get it next))\n\t))\n)\n\n(func destroy_polylines (param q (struct polyline))\n\t(if (! (?? q)) (then\n\t\t(return)\n\t))\n\t(let it (struct polyline) q)\n\t(while (?? it) (do\n\t\t(let lt (struct polyline) (get it next))\n\t\t(let jt (struct point) (get it head))\n\t\t(while (?? jt) (do\n\t\t\t(let kt (struct point) (get jt next))\n\t\t\t(free jt)\n\t\t\t(set jt kt)\n\t\t))\n\t\t(free it)\n\t\t(set it lt)\n\t))\n)\n\n(func reverse_polyline (param q (struct polyline))\n\t(if (|| (! (?? q)) (< (get q size) 2) ) (then\n\t\t(return)\n\t))\n\t(set (get q tail) next (get q head))\n\t(let it0 (struct point) (get q head))\n\t(let it1 (struct point) (get it0 next))\n\t(let it2 (struct point) (get it1 next))\n\t(for i 0 (< i (- (get q size) 1) ) 1 (do\n\t\t(set it1 next it0)\n\t\t(set it0 it1)\n\t\t(set it1 it2)\n\t\t(set it2 (get it2 next))\n\t))\n\t(let q_head (struct point) (get q head))\n\t(set q head (get q tail))\n\t(set q tail q_head)\n\t(null (get q tail) next)\n)\n\n(func cat_tail_polyline (param q0 (struct polyline)) (param q1 (struct polyline))\n\t(if (! (?? q1)) (then\n\t\t(return)\n\t))\n\t(if (! (?? q0)) (then\n\t\t(return)\n\t))\n\t(if (! (?? (get q0 head))) (then\n\t\t(set q0 head (get q1 head))\n\t\t(set q0 tail (get q1 tail))\n\t\t(return)\n\t))\n\t(set (get q0 tail) next (get q1 head))\n\t(set q0 tail (get q1 tail))\n\t(set q0 size (+ (get q0 size) (get q1 size)))\n\t(null (get q0 tail) next)\n)\n\n(func cat_head_polyline (param q0 (struct polyline)) (param q1 (struct polyline))\n\t(if (! (?? q1)) (then\n\t\t(return)\n\t))\n\t(if (! (?? q0)) (then\n\t\t(return)\n\t))\n\t(if (! (?? (get q0 head))) (then\n\t\t(set q0 head (get q1 head))\n\t\t(set q0 tail (get q1 tail))\n\t\t(return)\n\t))\n\t(set (get q1 tail) next (get q0 head))\n\t(set q0 head (get q1 head))\n\t(set q0 size (+ (get q0 size) (get q1 size)))\n\t(null (get q0 tail) next)\n)\n\n\n(func add_point_to_polyline (param q (struct polyline)) (param x int) (param y int) \n\t(let p (struct point) (alloc (struct point)))\n\t(set p x x)\n\t(set p y y)\n\t(null p next)\n\t(if (! (?? (get q head))) (then\n\t\t(set q head p)\n\t\t(set q tail p)\n\t)(else\n\t\t(set (get q tail) next p)\n\t\t(set q tail p)\n\t))\n\t(set q size (+ (get q size) 1))\n)\n\n(func prepend_polyline \n\t(param q0 (struct polyline)) \n\t(param q1 (struct polyline)) \n\t(result (struct polyline))\n\n\t(if (! (?? q0)) (then\n\t\t(return q1)\n\t))\n\t(set q1 next q0)\n\t(set q0 prev q1)\n\t(return q1)\n)\n\n\n;;================================\n;; RASTER SKELETONIZATION\n;;================================\n;; Binary image thinning (skeletonization) in-place.\n;; Implements Zhang-Suen algorithm.\n;; http://agcggs680.pbworks.com/f/Zhan-Suen_algorithm.pdf\n\n(func thinning_zs_iteration \n\t(param im (arr int)) \n\t(param W int) \n\t(param H int) \n\t(param iter int) \n\t(result int)\n\n\t(let diff int 0)\n\t(for i 1 (< i (- H 1)) 1 (do\n\t\t(for j 1 (< j (- W 1)) 1 (do\n\t\t\t(let p2 int (& (get im (+    (* (- i 1) W ) j )) 1))\n\t\t\t(let p3 int (& (get im (+ (+ (* (- i 1) W ) j )  1)) 1))\n\t\t\t(let p4 int (& (get im (+ (+ (*    i    W ) j )  1)) 1))\n\t\t\t(let p5 int (& (get im (+ (+ (* (+ i 1) W ) j )  1)) 1))\n\t\t\t(let p6 int (& (get im (+ (*    (+ i 1) W ) j )) 1))\n\t\t\t(let p7 int (& (get im (- (+ (* (+ i 1) W ) j )  1)) 1))\n\t\t\t(let p8 int (& (get im (- (+ (*    i    W ) j )  1)) 1))\n\t\t\t(let p9 int (& (get im (- (+ (* (- i 1) W ) j )  1)) 1))\n\t\t\t(let A int (+\n\t\t\t\t(&& (! p2) p3 ) (&& (! p3) p4 )\n\t\t\t\t(&& (! p4) p5 ) (&& (! p5) p6 )\n\t\t\t\t(&& (! p6) p7 ) (&& (! p7) p8 )\n\t\t\t\t(&& (! p8) p9 ) (&& (! p9) p2 )\n\t\t\t))\n\t\t\t(let B int (+ p2 p3 p4 p5 p6 p7 p8 p9))\n\t\t\t(let m1 int (? (= iter 0)\n\t\t\t\t(* p2 p4 p6)\n\t\t\t\t(* p2 p4 p8)\n\t\t\t))\n\t\t\t(let m2 int (? (= iter 0)\n\t\t\t\t(* p4 p6 p8)\n\t\t\t\t(* p2 p6 p8)\n\t\t\t))\n\t\t\t(if (&& (= A 1) (>= B 2) (<= B 6) (= m1 0) (= m2 0)) (then\n\t\t\t\t(set im (+ (* i W) j)\n\t\t\t\t\t(| (get im (+ (* i W) j)) 2)\n\t\t\t\t)\n\t\t\t))\n\t\t))\n\t))\n\n\t(for i 0 (< i (* H W)) 1 (do\n\t\t(let marker int (>> (get im i) 1))\n\t\t(let old int (& (get im i) 1))\n\t\t(set im i (& old (! marker)))\n\t\t(if (&& (! diff) (<> (get im i) old)) (then\n\t\t\t(set diff 1)\n\t\t))\n\t))\n\t(return diff)\n)\n\n(func thinning_zs \n\t(param im (arr int)) \n\t(param W int) \n\t(param H int) \n\n\t(let diff int 1)\n\t(while diff (do\n\t\t(set diff (& diff (call thinning_zs_iteration im W H 0)))\n\t\t(set diff (& diff (call thinning_zs_iteration im W H 1)))\n\t))\n)\n\n;;================================\n;; MAIN ALGORITHM\n;;================================\n\n;; check if a region has any white pixel\n(func not_empty\n\t(param im (arr int)) \n\t(param W int) (param H int) \n\t(param x int) (param y int)\n\t(param w int) (param h int)\n\t(result int)\n\n\t(for i y (< i (+ y h)) 1 (do\n\t\t(for j x (< j (+ x w)) 1 (do\n\t\t\t(if (get im (+ (* i W) j))(then\n\t\t\t\t(return 1)\n\t\t\t))\n\t\t))\n\t))\n\t(return 0)\n)\n\n;; merge ith fragment of second chunk to first chunk\n;; @param c0   fragments from  first  chunk\n;; @param c1i  ith fragment of second chunk\n;; @param sx   (x or y) coordinate of the seam\n;; @param isv  is vertical, not horizontal?\n;; @param mode 2-bit flag, \n;;             MSB = is matching the left (not right) end of the fragment from first  chunk\n;;             LSB = is matching the right (not left) end of the fragment from second chunk\n;; @return     matching successful?             \n;; \n(func merge_impl \n\t(param c0  (struct polyline))\n\t(param c1i (struct polyline))\n\t(param sx int)\n\t(param isv int)\n\t(param mode int)\n\t(result int)\n\n\t(let b0 int (> (& (>> mode 1) 1) 0 ))  ; match c0 left\n\t(let b1 int (> (&     mode    1) 0 ))  ; match c1 left\n\t(let c0j (struct polyline))\n\t(let md int 4) ;maximum offset to be regarded as continuous\n\n\t(let p1 (struct point) (? b1 (get c1i head) (get c1i tail) ))\n\t(if (> (call abs (- (? isv (get p1 y) (get p1 x) ) sx) ) 0) (then\n\t\t(return 0) ; not on the seam, skip\n\t))\n\t; find the best match\n\t(let it (struct polyline) c0)\n\t(while (?? it) (do\n\t\t(let p0 (struct point) (? b0 (get it head) (get it tail)) )\n\t\t(if (<= (call abs (- (? isv (get p0 y) (get p0 x) ) sx) ) 1) (then\n\t\t\t(let d int\n\t\t\t\t(call abs (-\n\t\t\t\t\t(? isv (get p0 x) (get p0 y) )\n\t\t\t\t\t(? isv (get p1 x) (get p1 y) )\n\t\t\t\t))\n\t\t\t)\n\t\t\t(if (< d md) (then\n\t\t\t\t(set c0j it)\n\t\t\t\t(set md d)\n\t\t\t))\n\n\t\t))\n\t\t(set it (get it next))\n\t))\n\t(if (?? c0j) (then ; best match is good enough, merge them\n\t\t(if (&& b0 b1) (then\n\t\t\t(call reverse_polyline c1i)\n\t\t\t(call cat_head_polyline c0j c1i)\n\t\t)(else (if (&& (! b0) b1) (then\n\t\t\t(call cat_tail_polyline c0j c1i)\n\t\t)(else (if (&& b0 (! b1)) (then\n\t\t\t(call cat_head_polyline c0j c1i)\n\t\t)(else\n\t\t\t(call reverse_polyline c1i)\n\t\t\t(call cat_tail_polyline c0j c1i)\n\t\t))))))\n\t\t(return 1)\n\t))\n\t(return 0)\n)\n\n;; merge fragments from two chunks\n;; @param c0   fragments from first  chunk\n;; @param c1   fragments from second chunk\n;; @param sx   (x or y) coordinate of the seam\n;; @param dr   merge direction, HORIZONTAL or VERTICAL?\n;; \n(func merge_frags\n\t(param c0 (struct polyline))\n\t(param c1 (struct polyline))\n\t(param sx int)\n\t(param dr int)\n\t(result (struct polyline))\n\n\t(if (! (?? c0))(then\n\t\t(return c1)\n\t))\n\t(if (! (?? c1))(then\n\t\t(return c0)\n\t))\n\t(let it (struct polyline) c1)\n\t(while (?? it) (do\n\t\t(let tmp (struct polyline) (get it next))\n\t\t(while 1 (do\n\t\t\t(if (= dr @HORIZONTAL) (then\n\t\t\t\t(if (call merge_impl c0 it sx 0 1) (then (break)))\n\t\t\t\t(if (call merge_impl c0 it sx 0 3) (then (break)))\n\t\t\t\t(if (call merge_impl c0 it sx 0 0) (then (break)))\n\t\t\t\t(if (call merge_impl c0 it sx 0 2) (then (break)))\n\t\t\t) (else\n\t\t\t\t(if (call merge_impl c0 it sx 1 1) (then (break)))\n\t\t\t\t(if (call merge_impl c0 it sx 1 3) (then (break)))\n\t\t\t\t(if (call merge_impl c0 it sx 1 0) (then (break)))\n\t\t\t\t(if (call merge_impl c0 it sx 1 2) (then (break)))\n\t\t\t))\n\t\t\t(set it tmp)\n\t\t\t(break)\n\t\t))\n\t\t(if (<> it tmp) (then\n\t\t\t(if (! (?? (get it prev))) (then\n\t\t\t\t(set c1 (get it next))\n\t\t\t\t(if (?? (get it next)) (then\n\t\t\t\t\t(null (get it next) prev)\n\t\t\t\t))\n\t\t\t)(else\n\t\t\t\t(set (get it prev) next (get it next))\n\t\t\t\t(if (?? (get it next)) (then\n\t\t\t\t\t(set (get it next) prev (get it prev))\n\t\t\t\t))\n\t\t\t))\n\t\t\t(free it)\n\t\t\t(set it tmp)\n\t\t))\n\t))\n\t(set it c1)\n\t(while (?? it) (do\n\t\t(let tmp (struct polyline) (get it next))\n\t\t(null it prev)\n\t\t(null it next)\n\t\t(set c0 (call prepend_polyline c0 it))\n\t\t(set it tmp)\n\t))\n\t(return c0)\n)\n\n;; recursive bottom: turn chunk into polyline fragments;\n;; look around on 4 edges of the chunk, and identify the \"outgoing\" pixels;\n;; add segments connecting these pixels to center of chunk;\n;; apply heuristics to adjust center of chunk\n;; \n;; @param x    left of   chunk\n;; @param y    top of    chunk\n;; @param w    width of  chunk\n;; @param h    height of chunk\n;; @return     the polyline fragments\n;; \n(func chunk_to_frags \n\t(param im (arr int)) \n\t(param W int) (param H int) \n\t(param x int) (param y int) \n\t(param w int) (param h int)\n\t(result (struct polyline))\n\n\t(let frags (struct polyline))\n\n\t(let fsize int 0) ; to deal with strokes thicker than 1px\n\t(let on int 0)\n\t(let li int -1)\n\t(let lj int -1)\n\n\t; walk around the edge clockwise\n\t(for k 0 (< k (+ h h w w -4)) 1 (do\n\t\t(let i int)\n\t\t(let j int)\n\t\t(if (< k w) (then\n\t\t\t(set i y)\n\t\t\t(set j (+ x k))\n\t\t)(else (if (< k (+ w h -1)) (then\n\t\t\t(set i (+ y k (- w) 1))\n\t\t\t(set j (+ x w -1))\n\n\t\t)(else (if (< k (+ w h w -2)) (then\n\t\t\t(set i (+ y h -1))\n\t\t\t(set j (+ x w (- k) w h -3))\n\t\t)(else\n\t\t\t(set i (+ y h (- k) w h w -4))\n\t\t\t(set j x)\n\t\t))))))\n\t\t(if (get im (+ (* i W) j)) (then ; found an outgoing pixel\n\t\t\t(if (! on) (then             ; left side of stroke\n\t\t\t\t(set on 1)\n\t\t\t\t(let f (struct polyline) (call new_polyline))\n\t\t\t\t(call add_point_to_polyline f j i)\n\t\t\t\t(call add_point_to_polyline f (+ x (/ w 2)) (+ y (/ h 2)))\n\t\t\t\t(set frags (call prepend_polyline frags f))\n\t\t\t\t(set fsize (+ fsize 1))\n\t\t\t))\n\n\t\t)(else\n\t\t\t(if on (then ; right side of stroke, average to get center of stroke\n\t\t\t\t(set (get frags head) x (/ (+ (get frags head x) lj) 2))\n\t\t\t\t(set (get frags head) y (/ (+ (get frags head y) li) 2))\n\t\t\t\t(set on 0)\n\t\t\t))\n\t\t))\n\t\t(set li i)\n\t\t(set lj j)\n\t))\n\t(if (= fsize 2) (then ; it's a crossroad, guess the intersection\n\t\t(let f (struct polyline) (call new_polyline))\n\t\t(call add_point_to_polyline f (get frags head x) (get frags head y))\n\t\t(call add_point_to_polyline f (get frags next head x) (get frags next head y))\n\t\t(call destroy_polylines frags)\n\t\t(set frags f)\n\t)(else (if (> fsize 2) (then\n\t\t(let ms int 0)\n\t\t(let mi int -1)\n\t\t(let mj int -1)\n\t\t; use convolution to find brightest blob\n\t\t(for i (+ y 1) (< i (+ y h -1)) 1 (do\n\t\t\t(for j (+ x 1) (< j (+ x w -1)) 1 (do\n\t\t\t\t(let s int (+\n\t\t\t\t\t(get im (+ (* i W) (- W) j -1))\n\t\t\t\t\t(get im (+ (* i W) (- W) j   ))\n\t\t\t\t\t(get im (+ (* i W) (- W) j  1))\n\t\t\t\t\t(get im (+ (* i W)       j -1))\n\t\t\t\t\t(get im (+ (* i W)       j   ))\n\t\t\t\t\t(get im (+ (* i W)       j  1))\n\t\t\t\t\t(get im (+ (* i W)    W  j -1))\n\t\t\t\t\t(get im (+ (* i W)    W  j   ))\n\t\t\t\t\t(get im (+ (* i W)    W  j  1))\n\t\t\t\t))\n\t\t\t\t(if (> s ms) (then\n\t\t\t\t\t(set mi i)\n\t\t\t\t\t(set mj j)\n\t\t\t\t\t(set ms s)\n\t\t\t\t)(else (if (&&\n\t\t\t\t\t(= s ms)\n\t\t\t\t\t(<\n\t\t\t\t\t\t(+\n\t\t\t\t\t\t\t(call abs (- j (+ x (/ w 2))))\n\t\t\t\t\t\t\t(call abs (- i (+ y (/ h 2))))\n\t\t\t\t\t\t)(+\n\t\t\t\t\t\t\t(call abs (- mj (+ x (/ w 2))))\n\t\t\t\t\t\t\t(call abs (- mi (+ y (/ h 2))))\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t)(then\n\t\t\t\t\t(set mi i)\n\t\t\t\t\t(set mj j)\n\t\t\t\t\t(set ms s)\n\t\t\t\t))))\n\t\t\t))\n\t\t))\n\t\t(if (<> mi -1) (then\n\t\t\t(let it (struct polyline) frags)\n\t\t\t(while (?? it) (do\n\t\t\t\t(set (get it tail) x mj)\n\t\t\t\t(set (get it tail) y mi)\n\t\t\t\t(set it (get it next))\n\t\t\t))\n\t\t))\n\t))))\n\t(return frags)\n)\n\n;; Trace skeleton from thinning result.\n;; Algorithm:\n;; 1. if chunk size is small enough, reach recursive bottom and turn it into segments\n;; 2. attempt to split the chunk into 2 smaller chunks, either horizontall or vertically;\n;;    find the best \"seam\" to carve along, and avoid possible degenerate cases\n;; 3. recurse on each chunk, and merge their segments\n;; \n;; @param x       left of   chunk\n;; @param y       top of    chunk\n;; @param w       width of  chunk\n;; @param h       height of chunk\n;; @param iter    current iteration\n;; @return        an array of polylines\n;; \n(func trace_skeleton\n\t(param im (arr int))\n\t(param W int)\n\t(param H int)\n\t(param x int)\n\t(param y int)\n\t(param w int)\n\t(param h int)\n\t(param iter int)\n\t(result (struct polyline))\n\n\t(let frags (struct polyline))\n\t(if (<= iter 0) (then ; gameover\n\t\t(return frags)\n\t))\n\t(if (&& (<= w CHUNK_SIZE) (<= h CHUNK_SIZE) ) (then ; recursive bottom\n\t\t(set frags (call chunk_to_frags im W H x y w h))\n\t\t(return frags)\n\t))\n\t(let ms int (+ W H)) ; number of white pixels on the seam, less the better\n\t(let mi int -1)      ; horizontal seam candidate\n\t(let mj int -1)      ; vertical   seam candidate\n\t(if (> h CHUNK_SIZE) (then  ; try splitting top and bottom\n\t\t(for i (+ y 3) (< i (+ y h -3)) 1 (do\n\t\t\t(if (||\n\t\t\t\t\t(get im (+ (*    i    W) x)) \n\t\t\t\t\t(get im (+ (* (- i 1) W) x))\n\t\t\t\t\t(get im (+ (*    i    W) x w -1))\n\t\t\t\t\t(get im (+ (* (- i 1) W) x w -1))\n\t\t\t)(then)(else\n\t\t\t\t(let s int 0)\n\t\t\t\t(for j x (< j (+ x w)) 1 (do\n\t\t\t\t\t(set s (+ s (get im (+ (*    i    W) j))))\n\t\t\t\t\t(set s (+ s (get im (+ (* (- i 1) W) j))))\n\t\t\t\t))\n\t\t\t\t(if (< s ms) (then\n\t\t\t\t\t(set ms s)\n\t\t\t\t\t(set mi i)\n\t\t\t\t)(else (if (&&\n\t\t\t\t\t(= s ms)\n\t\t\t\t\t(<\n\t\t\t\t\t\t(call abs (-  i (+ y (/ h 2))))\n\t\t\t\t\t\t(call abs (- mi (+ y (/ h 2))))\n\t\t\t\t\t)\n\t\t\t\t) (then\n\t\t\t\t; if there is a draw (very common), we want the seam to be near the middle\n\t\t\t\t; to balance the divide and conquer tree\n\t\t\t\t\t(set ms s)\n\t\t\t\t\t(set mi i)\n\t\t\t\t))))\n\t\t\t))\n\n\t\t))\n\t))\n\t(if (> w CHUNK_SIZE) (then ; same as above, try splitting left and right\n\t\t(for j (+ x 3) (< j (+ x w -3)) 1 (do\n\t\t\t(if (||\n\t\t\t\t\t(get im (+ (*    y    W)       j)) \n\t\t\t\t\t(get im (+ (* (+ y h) W) (- W) j))\n\t\t\t\t\t(get im (+ (*    y    W)       j -1))\n\t\t\t\t\t(get im (+ (* (+ y h) W) (- W) j -1))\n\t\t\t)(then)(else\n\t\t\t\t(let s int 0)\n\t\t\t\t(for i y (< i (+ y h)) 1 (do\n\t\t\t\t\t(set s (+ s (get im (+ (* i W) j))))\n\t\t\t\t\t(set s (+ s (get im (+ (* i W) j -1))))\n\t\t\t\t))\n\t\t\t\t(if (< s ms) (then\n\t\t\t\t\t(set ms s)\n\t\t\t\t\t(set mi -1) ; horizontal seam is defeated\n\t\t\t\t\t(set mj j)\n\t\t\t\t)(else (if (&&\n\t\t\t\t\t(= s ms)\n\t\t\t\t\t(<\n\t\t\t\t\t\t(call abs (-  j (+ x (/ w 2))))\n\t\t\t\t\t\t(call abs (- mj (+ x (/ w 2))))\n\t\t\t\t\t)\n\t\t\t\t) (then\n\t\t\t\t\t(set ms s)\n\t\t\t\t\t(set mi -1)\n\t\t\t\t\t(set mj j)\n\t\t\t\t))))\n\t\t\t))\n\n\t\t))\n\t))\n\t(let L0 int -1) (let L1 int) (let L2 int) (let L3 int)\n\t(let R0 int -1) (let R1 int) (let R2 int) (let R3 int)\n\t(let dr int  0)\n\t(let sx int)\n\t(if (&& (> h CHUNK_SIZE) (<> mi -1)) (then ; split top and bottom\n\t\t(set L0 x) (set L1 y ) (set L2 w) (set L3 (- mi y))\n\t\t(set R0 x) (set R1 mi) (set R2 w) (set R3 (+ y h (- mi)))\n\t\t(set dr @VERTICAL)\n\t\t(set sx mi)\n\t)(else (if (&& (> w CHUNK_SIZE) (<> mj -1)) (then ; split left and right\n\t\t(set L0 x ) (set L1 y) (set L2 (- mj x))       (set L3 h)\n\t\t(set R0 mj) (set R1 y) (set R2 (+ x w (- mj))) (set R3 h)\n\t\t(set dr @HORIZONTAL)\n\t\t(set sx mj)\n\t))))\n\t(if (&& (<> dr 0) (call not_empty im W H L0 L1 L2 L3)) (then\n\t\t(set frags (call trace_skeleton im W H L0 L1 L2 L3 (- iter 1)))\n\t))\n\t(if (&& (<> dr 0) (call not_empty im W H R0 R1 R2 R3)) (then\n\t\t(set frags (call merge_frags\n\t\t\tfrags\n\t\t\t(call trace_skeleton im W H R0 R1 R2 R3 (- iter 1))\n\t\t\tsx dr\n\t\t))\n\t))\n\t(if (&& (= mi -1) (= mj -1)) (then\n\t\t(set frags (call chunk_to_frags im W H x y w h))\n\t))\n\t(return frags)\n)\n\n\n(func print_bitmap\n\t(param im (arr int)) \n\t(param W int) \n\t(param H int) \n\t(for i 0 (< i H) 1 (do\n\t\t(local row str (alloc str \"\"))\n\t\t(for j 0 (< j W) 1 (do\n\t\t\t(<< row (? (get im (+ (* i W) j)) 'x' '.'))\n\t\t))\n\t\t(print row)\n\t))\n)\n\n\n(func polylines_to_svg \n\t(param q (struct polyline)) \n\t(param W int) (param H int) \n\t(result str)\n\n\t(let s str (alloc str \"<svg version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" width=\\\"\"))\n\t(<< s (cast W str))\n\t(<< s \"\\\" height=\\\"\")\n\t(<< s (cast H str))\n\t(<< s \"\\\">\")\n\t(if (! (?? q)) (then\n\t\t(return s)\n\t))\n\t(let it (struct polyline) q)\n\t(while (?? it) (do\n\t\t(<< s \"<path d=\\\"\")\n\t\t(let jt (struct point) (get it head))\n\t\t(while (?? jt) (do\n\t\t\t(if (= jt (get it head))(then\n\t\t\t\t(<< s \"M\")\n\t\t\t)(else\n\t\t\t\t(<< s \"L\")\n\t\t\t))\n\t\t\t(<< s (cast (get jt x) str))\n\t\t\t(<< s \",\")\n\t\t\t(<< s (cast (get jt y) str))\n\t\t\t(<< s \" \")\n\t\t\t(set jt (get jt next))\n\t\t))\n\t\t(<< s \"\\\" fill=\\\"none\\\" stroke=\\\"black\\\"/>\")\n\t\t(set it (get it next))\n\t))\n\t(<< s \"</svg>\")\n\t(return s)\n)\n\n(func main (result int)\n\t(let W int 34)\n\t(let H int 28)\n\t(let im (arr int) (alloc (arr int)\n\t\t0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n\t\t0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0\n\t\t0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0\n\t\t0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0\n\t\t0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0\n\t\t0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0\n\t\t0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0\n\t\t0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 0\n\t\t0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 0\n\t\t0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0\n\t\t0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0\n\t\t0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0\n\t\t0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0\n\t\t0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0\n\t\t0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0\n\t\t0 1 1 1 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0\n\t\t0 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0\n\t\t0 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0\n\t\t0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n\t\t0 1 1 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n\t\t0 0 1 1 1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n\t\t0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n\t\t0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n\t\t0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n\t\t0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0\n\t\t0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0\n\t\t0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0\n\t\t0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n\t))\n\t(call thinning_zs im W H)\n\t(call print_bitmap im W H)\n\t(let q (struct polyline))\n\t(set q (call trace_skeleton im W H 0 0 W H 999))\n\t(call print_polylines q)\n\t(call destroy_polylines q)\n\t(free im)\n\t(return 0)\n)","turing.wax":";; Universal Turing Machine Simulation\n;; A wax feature demo\n\n; enums for shift directions\n(@define STAY  0)\n(@define LEFT  1)\n(@define RIGHT 2)\n\n; datastructure for the transition function\n(struct transition\n  \t(let q_curr int) ; current state\n  \t(let q_targ int) ; target state\n\t(let sym_r  int) ; read symbol\n  \t(let sym_w  int) ; write symbol\n  \t(let shift  int) ; shift direction\n)\n\n; datastructure for the turing machine\n; (map int int) is used to represent the tape,\n; mapping position to symbol, to simulate \"infinite\" length.\n; tmin/tmax are tape extremas for visualization\n(struct machine\n\t(let state int) ; current state\n\t(let head  int)\n\t(let tape  (map int int))\n\t(let tmin  int) ; leftmost  visited tape position\n\t(let tmax  int) ; rightmost visited tape position\n)\n\n; simulate the turing machine for 1 step.\n(func step\n\t(param M (struct machine))\n\t(param D (arr (struct transition)))\n\t(let tape (map int int) (get M tape))\n\n\t; check each transition function, to see if conditions apply\n\t(for i 0 (< i (# D)) 1 (do\n\n\t\t(if (&&\n\t\t\t(= (get M state)           (get D i q_curr))\n\t\t\t(= (get tape (get M head)) (get D i sym_r ))\n\t\t) (then\n\t\t\t; execute the transition\n\t\t\t(set tape  (get M head) (get D i sym_w ))\n\t\t\t(set M state            (get D i q_targ))\n\t\t\t(if (= (get D i shift) @LEFT) (then\n\t\t\t\t(set M head (- (get M head) 1))\n\t\t\t)(else(if (= (get D i shift) @RIGHT) (then\n\t\t\t\t(set M head (+ (get M head) 1))\n\t\t\t))))\n\t\t\t(break)\n\t\t))\n\t\t\n\t))\n\t; expand tape boundries if necessary\n\t(if (< (get M head) (get M tmin)) (then\n\t\t(set M tmin (get M head))\n\t))\n\t(if (> (get M head) (get M tmax)) (then\n\t\t(set M tmax (get M head))\n\t))\n)\n\n; visualize the current state of turing machine\n; by printing ASCII drawing in the terminal\n(func draw (param M (struct machine))\n\t(let s str (alloc str \"\"))\n\t(for i (get M tmin) (<= i (get M tmax)) 1 (do\n\t\t(<< s (? (= i (get M head )) (get M state) ' ') )\n\t\t(<< s (?      (get M tape i) '1'           '_') )\n\t\t(<< s \"  \")\n\t))\n\t(print s)\n)\n\n; main turing machine simulation routine\n(func turing\n\t(param D (arr (struct transition)))\n\t(param q0 int) ; initial state\n\t(param q1 int) ; halting state\n\n\t; initialize\n\t(local M (struct machine) (alloc (struct machine)))\n\t(local tape (map int int) (alloc (map int int)))\n\t(set M state q0)\n\t(set M tape tape)\n\n\t(call draw M)\n\t\n\t; simulate\n\t(while 1 (do\n\t\t(call step M D)\n\t\t(call draw M)\n\t\t(if (= (get M state) q1) (then\n\t\t\t(break)\n\t\t))\n\t))\n)\n\n; helper for defining a transition\n; (allocate struct, fill in info, push to array)\n(func defn\n\t(param D (arr (struct transition)))\n\t(param q_curr int)  (param q_targ int)\n\t(param sym_r  int)  (param sym_w  int)\n\t(param shift  int)\n\t\n\t(let d (struct transition) (alloc (struct transition)))\n\t(set d q_curr q_curr)\n\t(set d q_targ q_targ)\n\t(set d sym_r  sym_r )\n\t(set d sym_w  sym_w )\n\t(set d shift  shift )\n\t\n\t(insert D (# D) d)\n)\n\n;; end of turing machine implementation\n;; ============================================================\n;; start of turing machine examples\n\n\n; 3-state, 2-symbol busy beaver\n; https://rosettacode.org/wiki/Universal_Turing_machine\n(func beaver3\n\t(local D (arr (struct transition)) \n\t  (alloc (arr (struct transition))))\n\t\n\t(call defn D 'A' 'B' 0 1 @RIGHT)\n\t(call defn D 'A' 'C' 1 1 @LEFT )\n\t(call defn D 'B' 'A' 0 1 @LEFT )\n\t(call defn D 'B' 'B' 1 1 @RIGHT)\n\t(call defn D 'C' 'B' 0 1 @LEFT )\n\t(call defn D 'C' 'H' 1 1 @STAY )\n\t\n\t(call turing D 'A' 'H')\n\n\t(for i 0 (< i (# D)) 1 (do\n\t\t(free (get D i))\n\t))\n)\n\n; 4-state, 2-symbol busy beaver\n; https://en.wikipedia.org/wiki/Busy_beaver\n(func beaver4\n\t(local D (arr (struct transition)) \n\t  (alloc (arr (struct transition))))\n\t\n\t(call defn D 'A' 'B' 0 1 @RIGHT)\n\t(call defn D 'A' 'B' 1 1 @LEFT )\n\t(call defn D 'B' 'A' 0 1 @LEFT )\n\t(call defn D 'B' 'C' 1 0 @LEFT )\n\t(call defn D 'C' 'H' 0 1 @RIGHT)\n\t(call defn D 'C' 'D' 1 1 @LEFT )\n\t(call defn D 'D' 'D' 0 1 @RIGHT)\n\t(call defn D 'D' 'A' 1 0 @RIGHT)\n\t\n\t(call turing D 'A' 'H')\n\n\t(for i 0 (< i (# D)) 1 (do\n\t\t(free (get D i))\n\t))\t\n)\n\n; run a turing machine in the main function for demo\n(func main (result int)\n\t(call beaver4)\n\t(return 0)\t\n)\n\t","vororelax.wax":";; Voronoi Relaxation\n;; with animated SVG\n;;\n;; This demo contains 3 parts:\n;; - Delaunay triangulation, a port of Paul Bourke's implementation\n;;   (http://paulbourke.net/papers/triangulate/triangulate.c)\n;;   This is the same as \"examples/delaunay.wax\", copy-pasted here because \n;;   wax Playground does not support (@include \"...\") yet \n;; - Voronoi diagram, computed by \"flipping\" the delaunay.\n;;   (For a better big-O, Fortune's Sweep algorithm can be used instead,\n;;   but since we already got the delaunay, plus it's easier, so... :)\n;; - Lloyd's relaxation algorithm, which iteratively spreads out \n;;   the voronoi sites more and more evenly \n;;   (https://en.wikipedia.org/wiki/Lloyd%27s_algorithm)\n;;\n;; Note: when running in the wax Playground, it might take a second to\n;;       compute all the frames, which might look like browser freezing\n\n(@include math)\n\n;; =========================================================================\n;; PART I: Delaunay Triangulation\n;; ported from Paul Bourke original C version:\n;; http://paulbourke.net/papers/triangulate/triangulate.c\n;; with original comments\n\n(@define X 0)\n(@define Y 1)\n(@define FALSE 0)\n(@define TRUE 1)\n(@define P1 0)\n(@define P2 1)\n(@define P3 2)\n(@define EPSILON 0.0000001)\n\n;; Return TRUE if a point (xp,yp) is inside the circumcircle made up\n;; of the points (x1,y1), (x2,y2), (x3,y3)\n;; The circumcircle centre is returned in (xc,yc) and the radius r\n;; NOTE: A point on the edge is inside the circumcircle\n(func circumcircle (param xp float) (param yp float)\n\t(param x1 float) (param y1 float) (param x2 float) (param y2 float) (param x3 float) (param y3 float)\n\t(param xcycr (vec 3 float)) (result int)\n\n\t(let m1 float) (let m2 float)\n\t(let mx1 float) (let mx2 float)\n\t(let my1 float) (let my2 float)\n\t(let dx float) (let dy float) (let drsqr float)\n\t(let fabsy1y2 float (call fabs (- y1 y2)))\n\t(let fabsy2y3 float (call fabs (- y2 y3)))\n\t(let xc float)\n\t(let yc float)\n\t(let rsqr float)\n\n\t(if (&& (< fabsy1y2 @EPSILON) (< fabsy2y3 @EPSILON)) (then\n\t\t(return 0)\n\t))\n\t(if (< fabsy1y2 @EPSILON) (then\n\t\t(set m2 (- (/ (- x3 x2) (- y3 y2))))\n\t\t(set mx2 (/ (+ x2 x3) 2.0))\n\t\t(set my2 (/ (+ y2 y3) 2.0))\n\t\t(set xc (/ (+ x2 x1) 2.0))\n\t\t(set yc (+ (* m2 (- xc mx2)) my2))\n\t)(else (if (< fabsy2y3 @EPSILON) (then\n\t\t(set m1 (- (/ (- x2 x1) (- y2 y1))))\n\t\t(set mx1 (/ (+ x1 x2) 2.0))\n\t\t(set my1 (/ (+ y1 y2) 2.0))\n\t\t(set xc (/ (+ x3 x2) 2.0))\n\t\t(set yc (+ (* m1 (- xc mx1)) my1))\n\t)(else\n\t\t(set m1 (- (/ (- x2 x1) (- y2 y1))))\n\t\t(set m2 (- (/ (- x3 x2) (- y3 y2))))\n\t\t(set mx1 (/ (+ x1 x2) 2.0))\n\t\t(set mx2 (/ (+ x2 x3) 2.0))\n\t\t(set my1 (/ (+ y1 y2) 2.0))\n\t\t(set my2 (/ (+ y2 y3) 2.0))\n\t\t(set xc (/ (+ (* m1 mx1) (- (* m2 mx2)) my2 (- my1) ) (- m1 m2) ))\n\t\t(if (> fabsy1y2 fabsy2y3) (then\n\t\t\t(set yc (+ (* m1 (- xc mx1)) my1))\n\t\t)(else\n\t\t\t(set yc (+ (* m2 (- xc mx2)) my2))\n\t\t))\n\t))))\n\t(set dx (- x2 xc))\n\t(set dy (- y2 yc))\n\t(set rsqr (+ (* dx dx) (* dy dy)))\n\t(set dx (- xp xc))\n\t(set dy (- yp yc))\n\t(set drsqr (+ (* dx dx) (* dy dy)))\n\n\t(set xcycr @X xc)\n\t(set xcycr @Y yc)\n\t(set xcycr 2 rsqr)\n\n\t(return (<= (- drsqr rsqr) @EPSILON))\n)\n\n;; Triangulation subroutine\n;; Takes as input vertices in array pxyz\n;; Returned is a list of triangular faces\n;; These triangles are arranged in a consistent clockwise order.\n;; The vertex array must be sorted in increasing x values\n(func delaunaytriangulate (param pxyz (arr (vec 2 float))) (result (arr (vec 3 int)))\n\t(let nv int (# pxyz))\n\t(let inside int)\n\t(let xp float) (let yp float)\n\t(let x1 float) (let y1 float)\n\t(let x2 float) (let y2 float)\n\t(let x3 float) (let y3 float)\n\t(let xmin float) (let xmax float)\n\t(let ymin float) (let ymax float)\n\t(let xmid float) (let ymid float)\n\t(let dx float) (let dy float) (let dmax float)\n\n\t(local xcycr (vec 3 float) (alloc (vec 3 float)))\n\t(local complete (arr int) (alloc (arr int)))\n\n\t(let v (arr (vec 3 int)) (alloc (arr (vec 3 int))))\n\n\t(if (< (# pxyz) 3) (then\n\t\t(return v)\n\t))\n\n\t;; Find the maximum and minimum vertex bounds.\n\t;; This is to allow calculation of the bounding triangle\n\t(set xmin (get pxyz 0 @X))\n\t(set ymin (get pxyz 0 @Y))\n\t(set xmax xmin)\n\t(set ymax ymin)\n\t(for i 1 (< i nv) 1 (do\n\t\t(if (< (get pxyz i @X) xmin) (then (set xmin (get pxyz i @X)) ))\n\t\t(if (> (get pxyz i @X) xmax) (then (set xmax (get pxyz i @X)) ))\n\t\t(if (< (get pxyz i @Y) ymin) (then (set ymin (get pxyz i @Y)) ))\n\t\t(if (> (get pxyz i @Y) ymax) (then (set ymax (get pxyz i @Y)) ))\n\t))\n\n\t(set dx (- xmax xmin))\n\t(set dy (- ymax ymin))\n\t(set dmax (? (> dx dy) dx dy))\n\t(set xmid (/ (+ xmax xmin) 2))\n\t(set ymid (/ (+ ymax ymin) 2))\n\t\n\t;; Set up the supertriangle\n\t;; This is a triangle which encompasses all the sample points.\n\t;; The supertriangle coordinates are added to the end of the\n\t;; vertex list. The supertriangle is the first triangle in\n\t;; the triangle list.\n\n\t(insert pxyz (# pxyz) (alloc (vec 2 float) \n\t\t(- xmid (* 2.0 dmax))\n\t\t(- ymid dmax)\n\t))\n\t(insert pxyz (# pxyz) (alloc (vec 2 float)\n\t\txmid\n\t\t(+ ymid (* 2.0 dmax))\n\t))\n\t(insert pxyz (# pxyz) (alloc (vec 2 float)\n\t\t(+ xmid (* 2.0 dmax))\n\t\t(- ymid dmax)\n\t))\n\t(insert v 0 (alloc (vec 3 int)\n\t\tnv\n\t\t(+ nv 1)\n\t\t(+ nv 2)\n\t))\n\n\t(insert complete 0 @FALSE)\n\t\n\t;; Include each point one at a time into the existing mesh\n\t(for i 0 (< i nv) 1 (do\n\t\t(set xp (get pxyz i @X))\n\t\t(set yp (get pxyz i @Y))\n\t\t\n\t\t(local edges (arr (vec 2 int)) (alloc (arr (vec 2 int))))\n\n\t\t;; Set up the edge buffer.\n\t\t;; If the point (xp,yp) lies inside the circumcircle then the\n\t\t;; three edges of that triangle are added to the edge buffer\n\t\t;; and that triangle is removed.\n\n\t\t(for j (- (# v) 1) (>= j 0) -1 (do\n\t\t\t(if (! (get complete j)) (then\n\t\t\t\t(set x1 (get pxyz (get v j @P1) @X))\n\t\t\t\t(set y1 (get pxyz (get v j @P1) @Y))\n\t\t\t\t(set x2 (get pxyz (get v j @P2) @X))\n\t\t\t\t(set y2 (get pxyz (get v j @P2) @Y))\n\t\t\t\t(set x3 (get pxyz (get v j @P3) @X))\n\t\t\t\t(set y3 (get pxyz (get v j @P3) @Y))\n\t\t\t\t(set inside (call circumcircle xp yp x1 y1 x2 y2 x3 y3 xcycr))\n\n\t\t\t\t(let xc float (get xcycr @X))\n\t\t\t\t(let r float (get xcycr 2))\n\t\t\t\t(if (&& (< xc xp) (> (* (- xp xc) (- xp xc)) r) ) (then\n\t\t\t\t\t(set complete j @TRUE)\n\t\t\t\t))\n\t\t\t\t(if inside (then\n\t\t\t\t\t(insert edges (# edges) (alloc (vec 2 int) (get v j @P1) (get v j @P2)))\n\t\t\t\t\t(insert edges (# edges) (alloc (vec 2 int) (get v j @P2) (get v j @P3)))\n\t\t\t\t\t(insert edges (# edges) (alloc (vec 2 int) (get v j @P3) (get v j @P1))) \n\t\t\t\t\t(free (get v j))\n\t\t\t\t\t(remove v j 1)\n\t\t\t\t\t(remove complete j 1)\n\t\t\t\t))\n\t\t\t))\n\t\t))\n\t\t;; Tag multiple edges\n\t\t;; Note: if all triangles are specified anticlockwise then all\n\t\t;;       interior edges are opposite pointing in direction.\n\t\t(for j 0 (< j (- (# edges) 1)) 1 (do\n\t\t\t(for k (+ j 1) (< k (# edges)) 1 (do\n\t\t\t\t(if (&&\n\t\t\t\t\t(= (get edges j @P1) (get edges k @P2))\n\t\t\t\t\t(= (get edges j @P2) (get edges k @P1))\n\t\t\t\t) (then\n\t\t\t\t\t(set (get edges j) @P1 -1)\n\t\t\t\t\t(set (get edges j) @P2 -1)\n\t\t\t\t\t(set (get edges k) @P1 -1)\n\t\t\t\t\t(set (get edges k) @P2 -1)\n\t\t\t\t))\n\t\t\t\t;; Shouldn't need the following, see note above\n\t\t\t\t(if (&&\n\t\t\t\t\t(= (get edges j @P1) (get edges k @P1))\n\t\t\t\t\t(= (get edges j @P2) (get edges k @P2))\n\t\t\t\t) (then\n\t\t\t\t\t(set (get edges j) @P1 -1)\n\t\t\t\t\t(set (get edges j) @P2 -1)\n\t\t\t\t\t(set (get edges k) @P1 -1)\n\t\t\t\t\t(set (get edges k) @P2 -1)\n\t\t\t\t))\n\t\t\t))\n\t\t))\n\t\t\n\t\t;; Form new triangles for the current point\n\t\t;; Skipping over any tagged edges.\n\t\t;; All edges are arranged in clockwise order.\n\t\t(for j 0 (< j (# edges)) 1 (do\n\t\t\t(if (||\n\t\t\t\t(< (get edges j @P1) 0)\n\t\t\t\t(< (get edges j @P2) 0)\n\t\t\t) (then) (else\n\t\t\t\t(insert v (# v) (alloc (vec 3 int)\n\t\t\t\t\t(get edges j @P1)\n\t\t\t\t\t(get edges j @P2)\n\t\t\t\t\ti\n\t\t\t\t))\n\t\t\t\t(insert complete (# complete) @FALSE)\n\t\t\t))\n\t\t\t(free (get edges j))\n\t\t))\n\t))\n\t;; Remove triangles with supertriangle vertices\n\t;; These are triangles which have a vertex number greater than nv\n\t(for i (- (# v) 1) (>= i 0) -1 (do\n\t\t(if (||\n\t\t\t(>= (get v i @P1) nv)\n\t\t\t(>= (get v i @P2) nv)\n\t\t\t(>= (get v i @p3) nv)\n\t\t)(then\n\t\t\t(free (get v i))\n\t\t\t(remove v i 1)\n\t\t))\n\t))\n\t(free (get pxyz (- (# pxyz) 1) ))\n\t(free (get pxyz (- (# pxyz) 2) ))\n\t(free (get pxyz (- (# pxyz) 3) ))\n\t(remove pxyz (- (# pxyz) 3) 3)\n\n\t(return v)\n)\n\n\n(func comparex (param v1 (vec 2 float)) (param v2 (vec 2 float)) (result int)\n\t(if (< (get v1 @X) (get v2 @X)) (then\n\t\t(return -1)\n\t)(else (if (> (get v1 @X) (get v2 @X)) (then\n\t\t(return 1)\n\t))))\n\t(return 0)\n)\n\n;; =========================================================================\n;; PART II: Voronoi from Delaunay\n;; A simple algorithm:\n;; - for every triangle in the triangulation, find its circumcenter \n;; - for every site who is a vertex of the triangle, insert the circumcenter \n;;   into its list of circumcenters, while maintaining the sorted order of the list\n;;   by angles (clockwise)\n;; - in the end, each list of circumcenters is a convex polygon, \n;;   a.k.a. \"region\"/\"cell\" of the site.\n;; LIMITATION: No special handling of sites near the outer rim of the diagram -- i.e.\n;;             No clipping by a box, etc. \n;;             However, as this demo shows, clipping effect can be simulated\n;;             by \"fencing\" around the border with arrays of equidistant points\n\n;; datastructure for a site\n(struct site\n  (let x float)\n  (let y float)\n\t(let angles (arr float)) ; angles of associated circumcenters, to keep them sorted\n\t(let cell (arr (vec 2 float)))\n)\n\n;; sort points by x coordinate, \n;; while applying the same permuatation to another array \n;; (e.g. mask/indices/metadata for the points)\n(func sortbyxf\n\t(param A (arr (vec 2 float))) \n\t(param inds (arr int)) \n\t(param lo int) (param hi int)\n\n\t(if (>= lo hi) (then\n\t\t(return)\n\t))\n\t(let pivot (vec 2 float) (get A lo))\n\t(let left  int lo)\n\t(let right int hi)\n\t(while (<= left right) (do\n\t\t(while (< (call comparex (get A left) pivot) 0) (do\n\t\t\t(set left (+ left 1))\n\t\t))\n\t\t(while (> (call comparex (get A right) pivot) 0) (do\n\t\t\t(set right (- right 1))\n\t\t))\n\t\t(if (<= left right) (then\n\t\t\t(let tmp (vec 2 float) (get A left))\n\t\t\t(set A left (get A right))\n\t\t\t(set A right tmp)\n\n\t\t\t(let tmp2 int (get inds left))\n\t\t\t(set inds left (get inds right))\n\t\t\t(set inds right tmp2)\n\n\t\t\t(set left  (+ left 1))\n\t\t\t(set right (- right 1))\n\t\t))\n\t))\n\t(call sortbyxf A inds lo right)\n\t(call sortbyxf A inds left hi)\n)\n\n;; add a vertex to a site's cell,\n;; keeping sorted order by angles\n(func siteaddvertex (param st (struct site)) (param x float) (param y float)\n  (let ang float (call atan2 \n\t\t(- y (get st y))\n\t\t(- x (get st x))\n\t))\n\t(let xy (vec 2 float) (alloc (vec 2 float) x y))\n  (let n int (# (get st cell)))\n\n  (for i 0 (< i n) 1 (do\n    (if (< ang (get st angles i)) (then\n      (insert (get st cell) i xy)\n      (insert (get st angles) i ang)\n      (return)\n    ))\n  ))\n\t(insert (get st cell) n xy)\n\t(insert (get st angles) n ang)\n)\n\n;; is point in convex polygon?\n;; this is to exclude some of the \"unbounded\" cells around the borders, where the site\n;; appears to be outside of the bounded portion\n;;     :\\\n;;   # : |\n;;     :/\n(func ptinconvex (param x float) (param y float) (param poly (arr (vec 2 float))) (result int)\n\t(for i 0 (< i (# poly)) 1 (do\n\t\t(let x0 float (get poly i 0))\n\t\t(let y0 float (get poly i 1))\n\t\t(let x1 float (get poly (% (+ i 1) (# poly)) 0))\n\t\t(let y1 float (get poly (% (+ i 1) (# poly)) 1))\n\t\t(let side float (-\n\t\t\t(* (- x x0) (- y1 y0)) (* (- x1 x0) (- y y0))\n\t\t))\n\t\t(if (> side 0) (then\n\t\t\t(return 0)\n\t\t))\n\t))\n\t(return 1)\n)\n\n;; exclude a cell if it doesn't have enough points to form a polygon, \n;; or if its site is outside of the bounded cell\n;; this happens around the borders, see above\n(func prunecell (param st (struct site))\n\t(let n int (# (get st cell)))\n\t(if (||\n\t\t(< n 3) \n\t\t(! (call ptinconvex (get st x) (get st y) (get st cell)))\n\t)(then\n\t\t(for i 0 (< i n) 1 (do\n\t\t\t(free (get st cell i))\n\t\t))\n\t\t(remove (get st cell) 0 n)\n\t))\n)\n\n;; make voronoi diagram from delaunay triangles\n(func makevoronoi (param pxyz (arr (vec 2 float))) (param triangles (arr (vec 3 int))) \n\t(result (arr (struct site)))\n\n  (let sites (arr (struct site)) (alloc (arr (struct site))))\n\t(local circ (vec 3 float) (alloc (vec 3 float)))\n\n  (for i 0 (< i (# pxyz)) 1 (do\n    (let st (struct site) (alloc (struct site)))\n    (set st x (get pxyz i 0))\n    (set st y (get pxyz i 1))\n\t\t(set st angles (alloc (arr float)))\n\t\t(set st cell (alloc (arr (vec 2 float))))\n    (insert sites (# sites) st)\n  ))\n  (for i 0 (< i (# triangles)) 1 (do\n    (let p0 int (get triangles i 0))\n    (let p1 int (get triangles i 1))\n    (let p2 int (get triangles i 2))\n\t\t\n\t\t(call circumcircle 0 0\n\t\t\t(get pxyz p0 0) (get pxyz p0 1)\n\t\t\t(get pxyz p1 0) (get pxyz p1 1)\n\t\t\t(get pxyz p2 0) (get pxyz p2 1)\n\t\t\tcirc\n\t\t)\n    (call siteaddvertex (get sites p0) (get circ 0) (get circ 1))\n    (call siteaddvertex (get sites p1) (get circ 0) (get circ 1))\n    (call siteaddvertex (get sites p2) (get circ 0) (get circ 1))\n  ))\n\t(for i 0 (< i (# sites)) 1 (do\n\t\t(call prunecell (get sites i))\n\t))\n  (return sites)\n)\n\n;; free memory for a list of sites\n(func freesites (param sites (arr (struct site)))\n\t(for i 0 (< i (# sites)) 1 (do\n\t\t(free (get sites i angles))\n\t\t(for j 0 (< j (# (get sites i cell))) 1 (do\n\t\t\t(free (get sites i cell j))\n\t\t))\n\t\t(free (get sites i cell))\n\t\t(free (get sites i))\n\t))\n\t(free sites)\n)\n\n;; =========================================================================\n;; PART III: Lloyd's Relaxation\n;; https://en.wikipedia.org/wiki/Lloyd%27s_algorithm\n;; A simple algrithm:\n;; - Find voronoi\n;; - Move site to centroid of each cell\n;; - Repeat\n\n\n;; find centroid of a convex shape\n;; reference: https://bell0bytes.eu/centroid-convex/\n(func convexcentroid (param poly (arr (vec 2 float))) (param ctrd (vec 2 float))\n\t(let n int (# poly))\n\t(let det float 0)\n\t(let j int 0)\n\t(let cx float 0)\n\t(let cy float 0)\n\t(for i 0 (< i n) 1 (do\n\t\t(set j (% (+ i 1) n))\n\t\t(let x0 float (get poly i 0))\n\t\t(let y0 float (get poly i 1))\n\t\t(let x1 float (get poly j 0))\n\t\t(let y1 float (get poly j 1))\n\n\t\t(let d float (- (* x0 y1) (* x1 y0)))\n\t\t(set det (+ det d))\n\t\t(set cx (+ cx (* d (+ x0 x1))))\n\t\t(set cy (+ cy (* d (+ y0 y1))))\n\t))\n\t(set cx (/ cx (* 3 det) ))\n\t(set cy (/ cy (* 3 det) ))\n\t(set ctrd 0 cx)\n\t(set ctrd 1 cy)\n)\n\n;; apply lloyd's relaxation for 1 iteration\n;; param fixedf: a mask indicating if a point is fixed, hence not to be moved\n;; modifies: the original list of points\n;; returns: a voronoi diagram, as a list of sites. (you need to free these after use)\n(func lloydrelax (param pxyz (arr (vec 2 float))) (param fixedf (arr int))\n\t(result (arr (struct site)))\n\t(call sortbyxf pxyz fixedf 0 (- (# pxyz) 1))\n\t\n\t(local triangles (arr (vec 3 int)) (call delaunaytriangulate pxyz))\n\t\n\t(let sites (arr (struct site)) (call makevoronoi pxyz triangles))\n\t(for i 0 (< i (# sites)) 1 (do\n\t\t(if (&& (! (get fixedf i)) (# (get sites i cell))) (then\n\t\t\t(call convexcentroid (get sites i cell) (get pxyz i))\n\t\t))\n\t))\n\t(for i 0 (< i (# triangles)) 1 (do\n\t\t(free (get triangles i))\n\t))\n\t(return sites)\n)\n\n;; =========================================================================\n;; PART IV: Test and Render\n;; Uses animated svg (fancy!)\n;; https://developer.mozilla.org/en-US/docs/Web/SVG/Element/animate\n\n\n; render a frame of the animated SVG\n(func renderframe (param w int) (param h int)\n\t(param sites (arr (struct site))) \n\t(param idx int) (param total int)\n\t(result str)\n\n\t(let s str (alloc str \"<g opacity=\\\"0\\\"><animate attributeName=\\\"opacity\\\" dur=\\\"5\\\" repeatCount=\\\"indefinite\\\" calcMode=\\\"linear\\\" values=\\\"0;\"))\n\t(for i 0 (< i total) 1 (do\n\t\t(<< s (? (= idx i) \"1;\" \"0;\"))\n\t))\n\t(<< s \"0\\\"/>\")\n\n\t(for i 0 (< i (# sites)) 1 (do\n\t\t(if (# (get sites i cell)) (then\n\t\t\t(<< s \"<path d=\\\"\")\n\t\t\t(for j 0 (< j (# (get sites i cell))) 1 (do\n\t\t\t\t(<< s (? j \"L\" \"M\"))\n\t\t\t\t(<< s (cast (get sites i cell j 0) str))\n\t\t\t\t(<< s \",\")\n\t\t\t\t(<< s (cast (get sites i cell j 1) str))\n\t\t\t\t(<< s \" \")\n\t\t\t))\n\t\t\t(<< s \"z\\\" fill=\\\"none\\\" stroke=\\\"black\\\"/>\")\n\t\t))\n\n\t\t(<< s \"<circle cx=\\\"\")\n\t\t(<< s (cast (get sites i x) str))\n\t\t(<< s \"\\\" cy=\\\"\")\n\t\t(<< s (cast (get sites i y) str))\n\t\t(<< s \"\\\" r=\\\"2\\\" fill=\\\"black\\\" />\")\n\t))\n\t(<< s \"</g>\")\n\t(return s)\n)\n\n;; test the whole thing\n(func main (result int)\n\t;; list of points\n\t(local pxyz (arr (vec 2 float)) (alloc (arr (vec 2 float))))\n\n\t;; dimensions\n\t(let w int 400)\n\t(let h int 400)\n\n\t;; first generate a bunch of fixed points to act as the border\n\t;; just a simple circle\n\t(let numfixed int 50)\n\t(for i 0 (< i numfixed) 1 (do\n\t\t(let a float (/ (* i 6.2831853072) numfixed))\n\t\t(insert pxyz (# pxyz) (alloc (vec 2 float)\n\t\t\t(+ (/ w 2) (* (call cos a) (/ w 2)))\n\t\t\t(+ (/ w 2) (* (call sin a) (/ w 2)))\n\t\t))\n\t))\n\n\t;; generate a bunch of random points in the circle\n\t;; (with rejection sampling) \n\t(for i 0 (< i 200) 1 (do\n\t\t(let x float (- (* (call random) w) (/ w 2)))\n\t\t(let y float (- (* (call random) h) (/ h 2)))\n\t\t(while (>= (+ (* x x) (* y y)) (* w w 0.25 0.8)) (do\n\t\t\t(set x (- (* (call random) w) (/ w 2)))\n\t\t\t(set y (- (* (call random) h) (/ h 2)))\n\t\t))\n\t\t(insert pxyz (# pxyz) (alloc (vec 2 float) \n\t\t\t(+ x (/ w 2)) \n\t\t\t(+ y (/ h 2))\n\t\t))\n\t))\n\n\t;; generate a mask for the fixed points so\n\t;; lloydrelax knows not to mess with them\n\t(local fixedfilter (arr int) (alloc (arr int)))\n\t(for i 0 (< i (# pxyz)) 1 (do\n\t\t(insert fixedfilter i (< i numfixed))\n\t))\n\n\t;; render the animated svg\n  (local svg str (alloc str \"<svg version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" width=\\\"\"))\n  (<< svg (cast w str))\n  (<< svg \"\\\" height=\\\"\")\n  (<< svg (cast h str))\n  (<< svg \"\\\">\")\n\t\n\t(let maxiter int 10)\n\t(for iter 0 (< iter maxiter) 1 (do\n\t\t(let sites (arr (struct site)) (call lloydrelax pxyz fixedfilter))\n\t\t(local s str (call renderframe w h sites iter maxiter))\n\t\t(<< svg s)\n\t\t(call freesites sites)\n\t))\n\t(<< svg \"</svg>\")\n\t(print svg)\n\n\t;; clean up\n\t(for i 0 (< i (# pxyz)) 1 (do\n\t\t(free (get pxyz i))\n\t))\n\n\t(return 0)\n)"}
</script>
<script>

function main(){

  CodeMirror.defineSimpleMode("wax", {
    meta:{
      lineComment: ';',
      comment: ';',
    },
    start: [
      {regex: /"(?:[^\\]|\\.)*?(?:"|$)/mi, token: "string"},
      {regex: /(?:return|result|insert|remove|extern|param|local|while|alloc|slice|print|break|func|then|else|call|cast|free|null|get|set|let|for|asm|if|do)\b/,
       token: "keyword"},
      {regex: /(?:@include|@if|@define|@pragma)\b/,
       token: "def"},
      {regex: /(?:int|float|arr|vec|struct|map)\b/,
       token: "type"},
      {regex: /0x[a-f\d]+|[-+]?(?:\.\d+|\d+\.?\d*)(?:e[-+]?\d+)?/i,
       token: "number"},
      {regex: /;.*/, token: "comment"},
      {regex: /[-+\/*=<>!\?\&\|\^\%\~\#]+/, token: "keyword"},
      {regex: /[\{\[\(]/, indent: true, token: "bracket"},
      {regex: /[\}\]\)]/, dedent: true, token: "bracket"},
      {regex: /[a-z$][\w$]*/, token: "variable-2"},
    ],
  });

  var CML = CodeMirror(document.getElementById("cl"), {
    lineNumbers:true,
    matchBrackets: true,
    theme:"dracula",
    mode:  "wax",
    indentWithTabs: true,
    indentUnit: 4,
    extraKeys:{
      'Ctrl-/': 'toggleComment',
      'Cmd-/': 'toggleComment'
    }

  });
  window.CML = CML;

  var CMR = CodeMirror(document.getElementById("cr"), {
    lineNumbers:true,
    matchBrackets: true,
    theme:"dracula",
    mode:  "javascript",
    typescript:true,
  });
  window.CMR = CMR;

  CML.setSize(null,null);
  CMR.setSize(null,null);


  
  var seltarg = document.getElementById("seltarg");
  var selexam = document.getElementById("selexam");
  var selreal = document.getElementById("selreal");
  var butcomp = document.getElementById("butcomp");
  var butrunc = document.getElementById("butrunc");

  selexam.value = "turing.wax";

  try{
    if (window.location.href.split("?")[1]){
      var args = {};
      window.location.href.split("?")[1].split("&").map(x=>x.split("=")).map(x=>{args[x[0]]=x[1]})
      console.log(args);
      if (args.example){
        document.querySelector('#selexam [value="' + args.example + '"]').selected = true;
      }
      if (args.to){
        document.querySelector('#seltarg [value="' + args.to + '"]').selected = true;
      }
    }
  }catch(e){
    console.log("cannot parse url query")
  }


  CML.on("change",function(e){
    if (selreal.value == "yes"){
      doCompile();
    }
  })

  butcomp.onclick = function(){
    doCompile();
  }
  butrunc.onclick = function(){
    doRun();
  }

  selexam.onchange = function(){
    CML.setValue(examples[selexam.value]);
    doCompile();
  }

  seltarg.onchange = function(){
    doCompile();
  }


  selexam.onchange();

  window.console_content = "";
  window.print = console.log;
  window.console.log = function(x){console_content+=x+"\n"}




  function doCompile(){
    if (window.transpile){
      var out;
      var targ = seltarg.value;
      var mode = ({
          "ts":"javascript",
          "c":"text/x-csrc",
          "cpp":"text/x-c++src",
          "java":"text/x-java",
          "py":"text/x-python",
          "cs":"text/x-csharp",
          "swift":"text/x-swift",
          "json":"javascript",
          "lua":"text/x-lua",
          "wat":"text/webassembly",
        })[targ];
      // print(mode);
      document.getElementById("crimg").innerHTML = "";
      try{
        out = transpile(targ,selexam.value,CML.getValue(),0);
        CMR.setOption("mode", mode);
        CMR.setOption("lineWrapping",false);
      }catch(e){
        out = console_content;
        CMR.setOption("mode", "text");
        CMR.setOption("lineWrapping",true);
      }
      console_content = "";
      CMR.setValue(out);
    }else{
      setTimeout(doCompile,1000);
    }
  }

  function doRun(){
    if (window.transpile){
      var tsCode = transpile('ts',selexam.value,CML.getValue(),0);
      var jsCode = window.ts.transpile(tsCode);
      console_content = "";
      eval(jsCode);
      
      if (console_content.startsWith("<svg")){
        document.getElementById("crimg").innerHTML = console_content;
        // CMR.setOption("lineWrapping",true);
      }
      // }else{
        CMR.setOption("lineWrapping",false);
      // }
      // }else{
        // document.getElementById("crimg").innerHTML = "";
        CMR.setOption("mode", "text");
        
        CMR.setValue(console_content);
      

    }else{
      setTimeout(doRun,1000);
    }
  }

  WAXC().then(function(waxc){
    window.transpile = waxc.cwrap('transpile', 'string', ['string','string','string','number'])
  })

}
main();
</script>
